Knowledge
How to sync files and directories with rsync
#CommandLine
Learn how to sync files and directories with rsync, including syncing over SSH, dry runs, deleting, excluding, and the trailing-slash gotcha.
Published by Mark van Eijk on June 23, 2026 · 3 minute read
- Why rsync instead of scp
- The basic local sync
- The trailing-slash gotcha
- Syncing over SSH
- Always dry-run first
- Mirroring with --delete
- Excluding files
- A practical deploy command
Why rsync instead of scp
When I need to move a directory between machines, my first instinct used to be scp. It works, but it copies everything every single time. The moment I started syncing a large project folder repeatedly, that got painfully slow.
rsync is smarter. It compares source and destination and only transfers the parts that actually changed (the deltas). The first sync is a full copy, but every sync after that is fast because it skips files that are already identical. That makes it perfect for backups and deploys. If you only need a one-off file copy, scp is still fine, but for anything you run more than once, reach for rsync.
The basic local sync
The command I use most is short:
rsync -av source/ destination/
The flags:
-ais archive mode. It's a bundle that preserves permissions, timestamps, symlinks, and ownership, and recurses into subdirectories. This is what you want 95% of the time.-vis verbose, so you see which files are being transferred.
Add -h if you want human-readable sizes in the output (-avh).
The trailing-slash gotcha
This one bites everyone once. A trailing slash on the source changes the meaning:
# Copies the CONTENTS of source/ into destination/
rsync -av source/ destination/
# Copies the source FOLDER itself into destination/ (destination/source/)
rsync -av source destination/
With the slash, you get destination/file.txt. Without it, you get destination/source/file.txt. When something ends up one level too deep, this is almost always why.
Syncing over SSH
rsync runs over SSH by default for remote paths, so syncing to a server is straightforward:
rsync -avz -e ssh local/ user@host:/var/www/app/
-zcompresses data during transfer, which helps a lot over slower connections.-e sshsets SSH as the transport. You can pass options here too, like a custom port:-e "ssh -p 2222".
Pulling from a server to your machine is just the two paths swapped:
rsync -avz user@host:/var/www/app/ ./backup/
If you haven't set up key-based access yet, see connecting to a server with SSH first so you're not typing a password on every sync.
Always dry-run first
Before any sync that deletes or overwrites, I run it with --dry-run (or -n). It shows exactly what would happen without touching a single file:
rsync -av --dry-run source/ destination/
Pair it with --progress once you're happy and want to watch a real transfer:
rsync -av --progress source/ destination/
Mirroring with --delete
By default rsync never removes files from the destination. If you want a true mirror, where files deleted from the source also disappear from the destination, add --delete:
rsync -av --delete source/ destination/
This is powerful and dangerous. Run it with --dry-run first, every time. A misplaced trailing slash plus --delete is how people wipe a backup.
Excluding files
You rarely want to sync everything. Skip node_modules, .git, and friends with --exclude:
rsync -avz --exclude '.git' --exclude 'node_modules' --exclude '*.log' \
./app/ user@host:/var/www/app/
For longer lists, put patterns in a file and use --exclude-from:
rsync -avz --exclude-from='.rsyncignore' ./app/ user@host:/var/www/app/
A practical deploy command
Putting it together, here's the kind of one-liner I keep around for deploying a build:
rsync -avz --delete --progress \
--exclude '.git' --exclude '.env' \
./public/ user@host:/var/www/app/public/
Run it once with --dry-run appended, confirm the file list, then run it for real. Once you've done that a couple of times, rsync becomes the tool you never think twice about.
Subscribe to our newsletter
Do you want to receive regular updates with fresh and exclusive content to learn more about web development, hosting, security and performance? Subscribe now!
Related articles
Argument list too long (Bash: /bin/rm)
Learn how to sync files and directories with rsync, including syncing over SSH, dry runs, deleting, excluding, and the trailing-slash gotcha.
How to install Composer packages locally
Learn how to sync files and directories with rsync, including syncing over SSH, dry runs, deleting, excluding, and the trailing-slash gotcha.