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

CommandDescription
wp-dev-sync watchWatch for file changes and auto-sync to remote
wp-dev-sync pushOne-time upload to remote server
wp-dev-sync pullOne-time download from remote server
wp-dev-sync setupCheck dependencies and test connection
wp-dev-sync tunnelOpen public URL for client previews
wp-dev-sync initCreate 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:

  1. Performs an initial full sync (pushes all files)
  2. Starts monitoring your LOCAL_PATH for file changes
  3. On any change (save, create, delete, rename), triggers a sync push
  4. Only transfers the delta (changed bytes) via rsync
  5. Continues until you press Ctrl+C

The file watcher adapts to your OS automatically:

OSWatcherLatency
macOSfswatch (FSEvents)~0.5s
Linuxinotifywait (inotify)~0.5s
WindowsPolling~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)
SpeedFast — delta transfer (~200 bytes per edit)Slower — full file transfer
SecurityEncrypted (SSH)Unencrypted (unless FTPS)
AuthSSH key (passwordless)Username + password
AvailabilityVPS, dedicated, some managed hostingNearly universal
Best forDaily development, watch modeShared 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 checkswp-dev-sync setup verifies 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)
  • rsync for SSH mode — choco install rsync / brew install rsync
  • lftp for 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.