It's Friday evening and the disk on the app server is at 95%. You run:
rsync -av --delete /srv/app/uploads/ /mnt/archive/uploads/
That one worked — the contents of uploads landed inside /mnt/archive/uploads/. So next week, migrating a server, you run what looks like the same command for the whole app directory:
rsync -av /srv/app /mnt/newserver/
and get /mnt/newserver/app/ — fine, that's what you wanted. But then you try to flatten a config dir into /etc/myapp/ and run rsync -av /srv/config /etc/myapp/, and now your systemd unit looks for /etc/myapp/config/settings.conf instead of /etc/myapp/settings.conf. The service fails to start on the new box. Nothing errored; rsync exited 0 both times. That's the worst part — there is no error message to grep for, just a destination tree with one extra (or one missing) directory level.
The reverse mistake is just as costly: you meant to back up the folder and its name (so you can restore multiple hosts side by side), used a trailing slash, and your --delete mirror quietly flattened two hosts' backups into one directory.
Treating source and source/ as the same argument. They're not. The trailing slash tells rsync "copy the contents of this directory", not "copy this directory."
The mental model is seductive because in every other shell context, a trailing slash is cosmetic. cd /var/log/ and cd /var/log are identical. Tab completion even adds the slash for you, so which one you end up typing is basically random. Your fingers have a decade of evidence that the slash doesn't matter, and rsync is the one tool that quietly breaks that assumption — for the source argument only, not the destination, which makes it even harder to internalize.
# Copy the CONTENTS of /var/log into /backup/log/
rsync -av /var/log/ /backup/log/
# Copy the FOLDER /var/log into /backup/ (so you get /backup/log/)
rsync -av /var/log /backup/
Walk through it:
-a is archive mode: recursive, plus preserves permissions, times, symlinks, and more. It's the default starting point for any copy you care about.-v is verbose: prints each file as it's transferred, so you can eyeball the destination paths as they stream by.source/ means "the things inside source", source means "source itself, as a directory".Before any destructive run (especially with --delete), do a dry run first:
# Preview exactly what would happen — transfers nothing
rsync -avn --delete /srv/app/uploads/ /mnt/archive/uploads/
-n (--dry-run) makes rsync print what it would do without touching the destination. It's one keystroke and it's the difference between "verified" and "hoped".
rsync uses the trailing slash as a "treat as directory contents" signal:
rsync src/ dst/ → for every entry inside src, copy it into dst.rsync src dst/ → copy src (a directory) into dst, creating dst/src.Under the hood, rsync builds a file list from each source argument before transferring anything. Without the slash, the argument names the directory itself, so the directory is the top item in the list and everything else nests under it. With the slash, rsync expands the argument into the directory's children — the file list starts one level down. The man rsync page states the equivalence directly: rsync -av /src/foo /dest and rsync -av /src/foo/ /dest/foo transfer the same files the same way. One character, decided entirely at file-list construction time, before a single byte moves.
This is the single most common rsync footgun. The man page calls it out in the first paragraphs; nobody reads it.
# Mirror /home to /backup, keeping folder structure
rsync -av --delete /home/ /backup/home/
# When in doubt, prepend -n to preview before you commit
-n (dry-run) to any rsync command the first time you run it. Make it a reflex before every --delete.--itemize-changes to see exactly what rsync is doing per file — the itemized output (>f for file transfer, *deleting for removals) makes dry-run previews readable.rsync -av -e ssh src/ user@host:/dst/ — the slash rules are identical for remote sources and destinations.man rsync once. It's two minutes and this footgun never bites you again.Get a fresh guide every Monday. £12/mo, £100/yr, or £250 lifetime.