What is WP Dev Sync? Sync your local development with your remote server.
If you’ve ever developed a WordPress theme on a remote server, you know the pain: open FileZilla, navigate to the theme folder, drag files, refresh the browser, repeat. Hundreds of times a day. wp-dev-sync kills that workflow forever.
The Problem
Shopify developers have had shopify theme dev for years — a CLI that watches your local files and syncs them to a remote store automatically. WordPress developers? We’re still stuck with FTP clients from 2005, manual uploads, and deployment workflows held together by prayers and sticky notes.
Sure, you could set up a full local environment with Docker, MAMP, or LocalWP. But what if your client’s site is on shared hosting? What if you need to iterate on a staging server that has specific plugins, data, or configurations you can’t replicate locally? You’re back to FileZilla.
wp-dev-sync is a CLI tool that bridges this gap. Edit theme files locally in your favorite editor, and they appear on your server in seconds. No manual uploads. No git-push-wait-for-CI cycles. Just save and it’s there.
What It Does
wp-dev-sync is a standalone CLI (installed via npm) that syncs a local directory to a remote server. It supports two protocols:
- SSH (rsync) — Delta transfer. Only the changed bytes are sent. Editing one line in a 50KB PHP file transfers ~200 bytes. This is the recommended option.
- FTP (lftp) — Full file mirror. Works with any hosting that provides FTP access (cPanel, Plesk, shared hosting). Slower, but universally available.
Core Commands
| Command | Description |
|---|---|
wp-dev-sync watch | Watch for file changes and auto-sync to remote |
wp-dev-sync push | One-time upload to remote server |
wp-dev-sync pull | One-time download from remote server |
wp-dev-sync setup | Check dependencies and test connection |
wp-dev-sync tunnel | Open public URL for client previews |
wp-dev-sync init | Create config files from templates |
Quick Start (5 Minutes)
Here’s the full setup from zero to syncing:
# Install globally
npm install -g wp-dev-sync
# Go to your WordPress project
cd ~/projects/my-wordpress-site
# Create config files (.env + .syncignore)
wp-dev-sync init
# Edit .env with your server credentials
nano .env
# Verify everything works
wp-dev-sync setup
# Start syncing!
wp-dev-sync watch
That’s it. Every time you save a file, it appears on your server automatically. The terminal shows you exactly what’s being synced, with file type indicators and timestamps.
Configuration
All configuration lives in a .env file in your project root:
# What to sync
LOCAL_PATH=./wp-content/themes/my-theme
REMOTE_PATH=/var/www/html/wp-content/themes/my-theme
# Connection
SYNC_PROTOCOL=ssh
REMOTE_USER=deploy
REMOTE_HOST=myserver.com
REMOTE_PORT=22
# FTP only
REMOTE_PASSWORD=your-password
# Behavior
SYNC_EXCLUDE=.git,node_modules,.DS_Store,*.log,.env
SYNC_DELETE=false
Example: cPanel Shared Hosting (FTP)
LOCAL_PATH=./wp-content/themes/my-theme
REMOTE_PATH=/home/cpanel-user/public_html/wp-content/themes/my-theme
SYNC_PROTOCOL=ftp
[email protected]
REMOTE_HOST=ftp.domain.com
REMOTE_PORT=21
REMOTE_PASSWORD=your-ftp-password
Example: VPS with SSH
LOCAL_PATH=./wp-content/themes/my-theme
REMOTE_PATH=/var/www/html/wp-content/themes/my-theme
SYNC_PROTOCOL=ssh
REMOTE_USER=deploy
REMOTE_HOST=myserver.com
REMOTE_PORT=22
For SSH, set up a key pair once and syncing is fully passwordless:
ssh-keygen -t ed25519
ssh-copy-id -p 22 [email protected]
The .syncignore File
For granular control over what gets excluded from sync, wp-dev-sync supports a .syncignore file — same concept as .gitignore, one pattern per line:
# .syncignore
node_modules
vendor
.git
.env
*.log
*.map
public/hot
public/.vite
.idea
.vscode
.DS_Store
The file is created automatically when you run wp-dev-sync init. It works alongside SYNC_EXCLUDE in your .env — patterns from both are merged, so you can use whichever approach fits your workflow (or both).
For SSH, wp-dev-sync passes the file directly to rsync via --exclude-from, which means you get full rsync glob pattern support. For FTP, patterns are converted to lftp-compatible regex internally.
Watch Mode: How It Works
The watch command is where the magic happens. Here’s what it does under the hood:
- Performs an initial full sync (pushes all files)
- Starts monitoring your
LOCAL_PATHfor file changes - On any change (save, create, delete, rename), triggers a sync push
- Only transfers the delta (changed bytes) via rsync
- Continues until you press Ctrl+C
The file watcher adapts to your OS automatically:
| OS | Watcher | Latency |
|---|---|---|
| macOS | fswatch (FSEvents) | ~0.5s |
| Linux | inotifywait (inotify) | ~0.5s |
| Windows | Polling | ~2s |
Native watchers are optional — if they’re not installed, wp-dev-sync falls back to polling mode automatically. On macOS and Linux you can install them for faster response, but it works out of the box on every platform.
The Terminal UI
One thing I wanted to get right was the developer experience in the terminal. wp-dev-sync shows you exactly what’s happening with a clean, visual output:
- Colored file type badges —
[PHP]in purple,[CSS]in cyan,[JS]in yellow - Timestamps on every sync operation
- Connection info panel showing protocol, target, watcher type
- Progress bars and spinners during preflight checks
- Rounded box borders and status indicators (checkmarks, warnings, errors)
It’s inspired by tools like Claude Code and Shopify CLI — the terminal should feel like a first-class interface, not an afterthought.
Tunnels: Share Previews Instantly
Need to show a client what the staging site looks like? wp-dev-sync can open a public tunnel to your remote server:
# In .env
TUNNEL_TOOL=cloudflared
TUNNEL_DOMAIN=staging.mysite.com
# Run
wp-dev-sync tunnel
This creates a temporary public URL (like https://random-words.trycloudflare.com) that proxies to your staging server. No DNS changes, no firewall rules. Supports both Cloudflare Tunnels (free) and ngrok.
SSH vs FTP: Which Should You Use?
| SSH (rsync) | FTP (lftp) | |
|---|---|---|
| Speed | Fast — delta transfer (~200 bytes per edit) | Slower — full file transfer |
| Security | Encrypted (SSH) | Unencrypted (unless FTPS) |
| Auth | SSH key (passwordless) | Username + password |
| Availability | VPS, dedicated, some managed hosting | Nearly universal |
| Best for | Daily development, watch mode | Shared hosting without SSH |
Bottom line: Use SSH if you can. Use FTP if you must. wp-dev-sync makes both work seamlessly.
Not Just Themes
While wp-dev-sync is built for WordPress theme development, it works with any directory. Sync a plugin, your entire wp-content, or even a non-WordPress project:
# Sync a plugin
LOCAL_PATH=./wp-content/plugins/my-plugin
REMOTE_PATH=/var/www/html/wp-content/plugins/my-plugin
# Sync full wp-content
LOCAL_PATH=./wp-content
REMOTE_PATH=/var/www/html/wp-content
# Sync a React build
LOCAL_PATH=./build
REMOTE_PATH=/var/www/html/myapp
Why Not Just Use rsync Directly?
You could. But wp-dev-sync wraps rsync (and lftp) with:
- File watching — you don’t need to run rsync manually every time you save
- .env config — no remembering long rsync flags and paths
- .syncignore — gitignore-style exclusion file
- Cross-platform — handles Windows path quirks, Git Bash PATH issues, OS-specific watchers
- FTP fallback — same workflow on hosting without SSH
- Preflight checks —
wp-dev-sync setupverifies dependencies and tests the connection before you start - Beautiful output — you actually see what’s happening
It’s the difference between raw git commands and a GitHub Desktop — the underlying tool is the same, but the experience is designed for the workflow.
Installation & Requirements
npm install -g wp-dev-sync
Requirements:
- Bash (Git Bash on Windows, Terminal on macOS/Linux)
rsyncfor SSH mode —choco install rsync/brew install rsynclftpfor FTP mode —choco install lftp/brew install lftp
That’s it. No Docker, no PHP, no Composer. Just bash and a sync tool.
Links
wp-dev-sync is open source (MIT). Built by Renan Diaz. If it saves you time, give it a star on GitHub.