Skip to main content

Linux command: rsync

16 July 2026

Sooner or later, every Linux user needs to copy a lot of files from one place to another: a website to a server, a home folder to a backup drive, a project between two machines. You can do it with cp or scp, but the moment you run the same copy a second time you feel the waste, because they copy everything again, every time. rsync was built to fix exactly that. It looks at what is already at the destination and transfers only the parts that changed, which makes it the quiet backbone of backups, deployments, and server migrations all over the world.

1. The Basics

The job of rsync is to make a destination look like a source, and to do it with the least possible work. You point it at a source and a destination, and it copies the files across. So far that is just cp. The difference shows up the second time you run it: rsync compares the two sides first and skips everything that is already identical, so a repeated sync of a large folder can finish in seconds even when only one file changed.

That single idea, "copy only the difference", is what makes rsync special. It works on one machine, between two disks, and across the network over SSH, all with the same command. It can preserve permissions, ownership, timestamps, and symbolic links exactly. It can delete files at the destination that no longer exist at the source, so the two sides truly match. And if the connection drops halfway through a huge transfer, it can pick up where it left off instead of starting over.

The command reads left to right, just like cp: the last argument is the destination, and everything before it is a source.

$ rsync -a Documents/ /backup/Documents/

The tool that copies only what changed. Behind that simple promise sits a clever differencing algorithm, a small but sharp set of rules about trailing slashes, and enough options to run anything from a one-line backup to a full server migration.

This article starts with the simplest local copy and builds up to remote transfers over SSH, mirroring with deletes, excluding files, and the delta-transfer trick that lets rsync update a large file by sending only a few kilobytes. By the end you will understand not just how to run rsync, but why it does so little work.

The right mental model: rsync does not "copy files", it synchronises two locations. Every run asks the same question, "what is different?", and moves only that. The danger, as with cp, is always at the destination.

Back to top

2. Where the Name Comes From

The name rsync is a blend of remote and sync (short for synchronise). It was designed from the start to keep files in sync between a local and a remote machine, and the name says exactly that.

rsync  =  Remote SYNC

It replaced an older, dumber tool called rcp ("remote copy"), which copied whole files over the network with no cleverness at all. The extra letters in rsync are a small promise: this is not just a remote copy, it is a remote sync that pays attention to what is already there. The name has stuck for nearly thirty years because it still describes the tool perfectly.

Back to top

3. A Short History

Unlike cp and ls, which reach back to the first days of Unix, rsync is a relatively modern tool. Andrew Tridgell and Paul Mackerras released the first version in 1996. The heart of it is the rsync algorithm, a method for updating a file over a slow network link by sending only the changed pieces. Tridgell described it in a 1996 technical report and later in his PhD thesis. That algorithm is still what makes rsync worth using today.

EraMilestone
1996 Andrew Tridgell and Paul Mackerras release rsync, replacing rcp
Late 1990s The rsync delta-transfer algorithm is published and refined
2008 rsync 3.0 adds incremental recursion: it starts transferring before scanning the whole tree
2020 rsync 3.2 adds faster checksums (xxhash) and better compression (zstd)
Today rsync 3.2.x, protocol 31, ships on virtually every Linux distribution

Because the algorithm was the interesting part, rsync became more than a command: it is also a lightweight protocol. You will meet it as a plain local copy, as a transfer tunnelled over SSH, and as a network service (an "rsync daemon") that public mirrors use to distribute software. This article focuses on the two you will use most: local copies and copies over SSH.

Most classic Unix tools do one job in one place. rsync is unusual because it also carries a network protocol and a differencing algorithm inside a single command, which is why one tool can back up a laptop, deploy a website, and mirror an archive.

Back to top

4. Simple Use Cases

4.1 The Simplest Possible Sync

Give rsync a source, a destination, and the -a flag, and it copies the source into the destination. In the examples below, the line that starts with $ is what you type; the lines under it are what rsync prints back.

$ rsync -a project/ /backup/project/

Nothing is printed, which is the normal Unix way of saying "it worked". The -a flag (short for archive) is the flag you will use almost every time. It means "copy recursively and keep everything as it is": subfolders, permissions, timestamps, and symbolic links. For now, treat rsync -a as the everyday starting point; section 5 opens it up.

4.2 The Trailing Slash Rule

This is the one rule about rsync that everyone must learn, because it quietly changes where your files land. A trailing slash on the source means "the contents of this directory". No trailing slash means "this directory itself".

$ rsync -a src/ dst/     # copies the CONTENTS of src into dst
$ rsync -a src  dst/     # copies the DIRECTORY src, giving dst/src

You can prove it to yourself in a few seconds:

$ rsync -a src/ dst1/
$ ls dst1
a.txt  b.txt  sub

$ rsync -a src dst2/
$ ls dst2
src

The first command fills dst1 with the files that were inside src. The second one places src as a subfolder inside dst2. When a backup script mysteriously produces backup/project/project, a missing or extra slash is almost always the reason. The slash on the destination does not matter in the same way; it is the source slash that decides the layout.

Here is a trap I ran into myself, backing up my own home folder to an external disk, and it can quietly ruin a backup. It is tempting to reach for a wildcard instead of a trailing slash, which is exactly what I did:

$ rsync -av /home/peter/* /media/peter/writable/    # looks right, is not

The problem is that the * is expanded by the shell, before rsync ever runs, and a plain * does not match names that begin with a dot. So every hidden file and folder in the home directory (.bashrc, .ssh, .config, .gnupg) is silently left out. You can see it happen with echo:

$ echo /home/peter/*
/home/peter/Documents /home/peter/notes.txt     # notice: no .bashrc, no .ssh

What makes this dangerous is that it looks like it worked. The visible files and folders copy across fine, and hidden files inside those folders come along too, because rsync recurses into any directory the shell did hand it. Only the top-level dotfiles disappear, which are exactly the ones that hold your settings, keys, and credentials. In my case the external drive ended up with all my documents but none of my configuration, and I only noticed later. The fix is the trailing-slash form, which passes the directory itself to rsync and lets it walk the whole tree, hidden files and all:

$ rsync -av /home/peter/  /media/peter/writable/   # copies EVERYTHING, dotfiles included

Whenever you copy "a whole folder", prefer source/ over source/*. The trailing slash asks rsync to select the files; the wildcard asks the shell, and the shell hides your dotfiles.

4.3 Looking Before You Leap: -v and -n

Because rsync can delete and overwrite, it is worth seeing what it will do before it does it. Two flags make it talkative and cautious.

The -v flag (short for verbose) lists each file as it is transferred:

$ rsync -av src/ dst/
sending incremental file list
./
a.txt
b.txt
sub/
sub/c.txt

sent 308 bytes  received 88 bytes  792.00 bytes/sec
total size is 17  speedup is 0.04

The -n flag (short for dry-run) is the safety net. It shows exactly what would happen, but changes nothing. Combine it with -v and you get a preview:

$ rsync -avn src/ dst/
sending incremental file list
a.txt
b.txt
sub/c.txt

sent 163 bytes  received 32 bytes  390.00 bytes/sec
total size is 17  speedup is 0.09 (DRY RUN)

Notice the (DRY RUN) marker at the end. Get into the habit of running any new or risky rsync with -avn first, reading the list, and only then removing the n. This single habit prevents most rsync accidents.

4.4 Readable Sizes: -h

Raw byte counts in the summary are hard to read. The -h flag (short for human-readable) turns them into K, M, and G:

$ rsync -ah --stats bigfolder/ /backup/bigfolder/
...
Total file size: 1.42G bytes
Total transferred file size: 12.043M bytes

That second number is the point of rsync in one line: the folder is 1.42 GB, but only 12 MB actually changed, so only 12 MB was sent.

Back to top

5. Moderate Use Cases

5.1 What -a Really Means

The archive flag is not magic; it is a bundle of smaller flags. Knowing what is inside it helps you understand what rsync keeps and what it drops.

-a  =  -rlptgoD
LetterShort forKeeps
-r recursive Descends into every subdirectory
-l links Copies symbolic links as links, not as their targets
-p perms Preserves permissions (the mode bits)
-t times Preserves modification times
-g group Preserves the group
-o owner Preserves the owner (needs root)
-D devices Preserves device files and special files (needs root)

Keeping timestamps matters more than it looks. On the next run, rsync decides whether a file changed by comparing size and modification time. If -t did not preserve the time, every file would look new next time and rsync would copy everything again, throwing away its main advantage. This is why you should almost always include -a (or at least -t) rather than a bare -r.

One thing to notice: -a does not include -A (ACLs), -X (extended attributes), or -H (hard links). Those are separate, and section 6 covers them.

5.2 Copying Over the Network: SSH

The "r" in rsync is for remote, and this is where it shines. To copy to another machine, put user@host: in front of the remote path. By default rsync tunnels the transfer over SSH, so it is as secure as a normal SSH login.

$ rsync -a site/ This email address is being protected from spambots. You need JavaScript enabled to view it.:/var/www/site/   # push to a server
$ rsync -a This email address is being protected from spambots. You need JavaScript enabled to view it.:/var/www/site/ site/   # pull from a server

Whichever side has the host: prefix is the remote one. To pass options to SSH, such as a non-standard port or a specific key, use the -e flag (short for rsh, the remote shell):

$ rsync -a -e "ssh -p 2222" site/ This email address is being protected from spambots. You need JavaScript enabled to view it.:/var/www/site/

5.3 Compressing the Transfer: -z

The -z flag (short for compress) squeezes the data before sending it over the wire. On a slow or metered network this can speed up transfers of text, code, and other compressible files a lot.

$ rsync -az site/ This email address is being protected from spambots. You need JavaScript enabled to view it.:/var/www/site/

Use -z for remote transfers. Skip it for local copies and for folders full of already-compressed files (JPEGs, videos, ZIPs, most media): compressing them again just burns CPU for no gain.

5.4 Resuming and Watching Progress: -P

A big transfer over a shaky connection can fail halfway. The -P flag turns on two helpers at once: --partial (keep the half-transferred file so the next run can finish it) and --progress (show a live progress line per file).

$ rsync -aP bigfile.iso This email address is being protected from spambots. You need JavaScript enabled to view it.:/data/
bigfile.iso
  1,048,576  32%   12.4MB/s    0:00:04

Without --partial, an interrupted transfer of a large file starts again from zero next time. With it, rsync keeps what it already sent and resumes. For any transfer that takes more than a few seconds, -P is a friend.

The progress line from -P shows one bar per file. When you are copying thousands of files and want a single bar for the whole job, use --info=progress2 instead:

$ rsync -a --info=progress2 src/ dst/
     10,000,025 100%    1.16GB/s    0:00:00 (xfr#6, to-chk=0/8)

The to-chk=0/8 at the end counts how many files are still left to check, so you can watch the run wind down to zero.

5.5 Making the Destination Match Exactly: --delete

By default rsync only adds and updates; it never removes anything from the destination. So if you delete a file at the source, the old copy quietly lingers at the destination. The --delete flag makes the destination a true mirror by removing files that no longer exist at the source.

$ rsync -avn --delete src/ dst/
sending incremental file list
deleting old-report.txt
...
(DRY RUN)

This is powerful and sharp. --delete plus a wrong path or a missing trailing slash can wipe files you meant to keep. Always run it with -n first and read the deleting lines before you trust it. Used carefully, it is exactly how you keep a backup or a deployed website perfectly in step with the source.

Back to top

6. Advanced Use Cases

6.1 Leaving Things Out: --exclude

Real projects contain things you do not want to copy: caches, logs, dependency folders, temporary files. The --exclude option skips anything matching a pattern, and you can give it more than once.

$ rsync -a --exclude '*.log' --exclude 'cache/' src/ dst/

For a long list, keep the patterns in a file and read them with --exclude-from:

$ rsync -a --exclude-from='ignore.txt' src/ dst/

The patterns work a lot like .gitignore rules: a trailing slash means "a directory", a leading slash anchors the pattern to the top of the transfer, and * matches within one path level. There is a matching --include for the rarer case where you want to exclude almost everything but keep a few things back.

6.2 Extra Metadata: -A, -X, and -H

The archive flag -a keeps the everyday metadata, but three important things are left out on purpose because they cost extra work.

FlagShort forPreserves
-A acls Access control lists (fine-grained permissions)
-X xattrs Extended attributes (SELinux contexts, custom metadata)
-H hard-links Hard links, keeping shared files shared instead of duplicated

When you are backing up a whole system or migrating a server and want the copy to be truly faithful, the common recipe is rsync -aAXH. For an ordinary folder of documents, plain -a is enough.

6.3 Comparing by Content, Not Clock: -c

By default rsync decides a file is unchanged when its size and modification time both match. That is fast, but it can be fooled: a file edited and saved back to the same size within the same second, or a file whose timestamp was reset, can slip through. The -c flag (short for checksum) makes rsync read every file on both sides and compare a strong checksum instead.

$ rsync -avc src/ dst/     # compare by checksum, ignore size and time

This is slower, because it has to read all the data, but it is the honest way to answer "are these two folders really identical?" It is worth knowing about for verification runs, though not for everyday syncs.

6.4 Reading the Itemized Output: -i

The -i flag (short for itemize-changes) prints a compact code beside each file that tells you exactly why it was transferred. It looks cryptic at first, but it repays a minute of study.

$ rsync -ain src/ dst/
>f+++++++++ newfile.txt
>f..t...... changed.txt
.d..t...... sub/

Read the string left to right. The first character is the action: > means a file is being received (sent to the destination), and . means the item itself is not being updated, only an attribute. The second character is the type: f for a file, d for a directory. The rest are the reasons: c checksum, s size, t time, p permissions, o owner, g group. A row of +++++++++ means the file is brand new. So >f..t...... reads as "send this file because its time differs", and >f+++++++++ reads as "this file is new".

6.5 Being a Good Neighbour: --bwlimit and --stats

A full-speed rsync can saturate a network link and slow everything else down. The --bwlimit option caps the transfer rate, which is polite on a shared or production connection.

$ rsync -az --bwlimit=5m site/ This email address is being protected from spambots. You need JavaScript enabled to view it.:/var/www/site/  # cap at 5 MB/s

The --stats option prints a detailed report at the end, which is useful in scripts and logs to see how much really moved:

$ rsync -a --stats src/ dst/
Number of files: 5 (reg: 3, dir: 2)
Number of regular files transferred: 3
Total file size: 25 bytes
Total transferred file size: 25 bytes
...

6.6 Writing in Place and Sparse Files: --inplace and -S

By default rsync writes each updated file to a temporary copy and then renames it over the old one. That is safe, because an interrupted transfer never leaves a half-written file, but it needs room for both versions and it breaks any hard links pointing at the original. The --inplace option writes the changes straight into the existing file instead. It saves space, keeps hard links intact, and works well with the delta algorithm for large files that change only a little, such as database dumps, VM images, and append-only logs.

$ rsync -a --inplace bigdb.sql This email address is being protected from spambots. You need JavaScript enabled to view it.:/backups/

The trade-off is safety: if the transfer is interrupted, the destination file is left partly updated, so use --inplace only where that risk is acceptable.

The -S flag (short for sparse) handles files that contain long runs of zero bytes, such as disk images and some database files. It writes those runs as real "holes" in the filesystem rather than as blocks of zeros, so the copy can take far less space than the file's apparent size. (Older rsync versions, before 3.1.3, refused to combine -S with --inplace; current versions allow it.)

6.7 Beyond SSH: The rsync Daemon

SSH is the usual way to reach another machine, but rsync can also talk to a dedicated rsync daemon running on the far side. This is the mode the big public mirrors use to hand out Linux distributions to thousands of people at once. You recognise it by a double colon (or an rsync:// URL) and a module name instead of a filesystem path:

$ rsync -av rsync://mirror.example/debian/ /srv/mirror/debian/
$ rsync -av mirror.example::debian/ /srv/mirror/debian/   # same thing

A single colon (host:path) means "connect over SSH"; a double colon (host::module) means "connect to the rsync daemon". The daemon listens on port 873 and is configured in /etc/rsyncd.conf, where each module maps a name to a directory and its access rules. The daemon can be faster than SSH because it skips the encryption overhead, but that also means the traffic is unencrypted, so it suits public, read-only mirrors far more than private backups. For anything sensitive, stay with SSH.

Back to top

7. Something Most Users Do Not Know

7.1 The Delta-Transfer Algorithm: Sending Only the Changes

Here is the idea that makes rsync famous, and that most people use every day without knowing it exists. When rsync updates a file that already exists at the destination, it does not resend the whole file. It sends only the changed pieces, even inside a single large file.

It works like this. The receiving side splits its existing copy into fixed-size blocks and computes two checksums for each block: a fast "rolling" checksum and a strong one. It sends those to the sender. The sender then slides a window byte by byte through its own newer version of the file, using the cheap rolling checksum to spot places that match a block the receiver already has. Where a block matches, rsync sends just a short "you already have this block" reference. Only the genuinely new bytes travel across the network.

This is why appending one line to a 1 GB log file and syncing it can send only a few kilobytes. rsync found that almost every block was unchanged and sent references to them instead of the data.

There is a surprising twist: this clever algorithm is turned off for local copies. When both sides are on the same machine, reading the whole file to compute checksums is usually slower than just copying it, so rsync defaults to --whole-file (-W) locally and simply writes the file out. The delta algorithm earns its keep on slow network links, which is exactly what it was designed for.

This is the trick behind many "time machine" style backup systems, and it feels like magic the first time you see it. The --link-dest option points rsync at a previous backup. Any file that has not changed since then is not copied at all: instead, rsync creates a hard link to the file in the old backup, which takes essentially no extra space.

$ rsync -a --delete --link-dest=/backups/monday \
        src/ /backups/tuesday/

The result is a folder tuesday that looks like a complete, full backup of everything. But on disk, only the files that actually changed since Monday take new space; everything else is a shared hard link back into Monday's backup. You can keep daily snapshots for a month, each one browsable as a full copy, while using little more space than a single copy plus the changes. Delete an old snapshot and only its unique files are freed, because the rest are still linked from newer ones.

7.3 Knowing Where rsync Stops

Part of expertise is knowing when another tool fits better. rsync is superb at syncing file trees, but it is not the answer to everything.

NeedUseWhy
A quick one-off local copy cp Less to type, and no checksum overhead for a single copy
A single file to a server, once scp Simple when there is nothing to compare or resume
Bundle a tree into one archive tar Packs the whole structure into a single file for storage or transfer
Version history of a project git Tracks every change over time, not just the latest state
Clone a whole disk or partition dd Copies raw blocks, including the filesystem itself
Deduplicated, encrypted backups borg / restic Store each unique block once and encrypt it, so a month of snapshots stays small
Sync to cloud storage rclone Speaks the APIs of S3, Google Drive, and dozens of other providers, with an rsync-like feel
Continuous two-way sync Syncthing Keeps folders on several devices in step automatically in the background, both directions

The last three are modern tools built for jobs rsync was never meant to do: rsync is one-directional and stateless, so it does not deduplicate across backups, speak cloud APIs, or merge changes from two sides. Learn rsync anyway. Once you are comfortable with it, it quietly replaces a whole shelf of copy scripts, because it is the same command whether you are backing up a laptop, deploying a website, or moving a server to new hardware.

Back to top

8. Best Practices

  • Preview with -avn first. For any new or risky command, especially with --delete, run it as a dry run, read the list, and only then remove the n.
  • Master the trailing slash. src/ means "the contents", src means "the folder itself". This one rule decides where every file lands.
  • Use -a as your default, and add -z for remote transfers, -P for large ones, and -AXH when you need a truly faithful system copy.
  • Be careful with --delete. It makes the destination match the source exactly, including removing files. A wrong path can erase real data, so dry-run it every time.
  • Keep timestamps. Always preserve modification times (part of -a), or rsync will resend everything on the next run and lose its whole advantage.
  • Reach for the manual without hesitation. The rsync manual is long because the tool is deep. Typing man rsync the moment a question comes up is the habit that separates beginners from professionals.
$ man rsync            # the full manual page (long, and worth it)
$ rsync --help         # a quick flag summary
Back to top

9. Common Mistakes

9.1 Three Common Myths

MythReality
"rsync src dst and rsync src/ dst are the same." The trailing slash on the source changes the layout: contents versus the folder itself.
"rsync removes deleted files automatically." It never deletes unless you add --delete. By default it only adds and updates.
"rsync always sends only the changed bytes." The delta algorithm is off for local copies and for brand-new files, which are sent whole.
"rsync dir/* dst/ copies everything in dir." The shell expands * and skips top-level dotfiles. Use dir/ so rsync selects the files itself, hidden ones included.

9.2 Other Traps to Avoid

  • The double-nesting surprise. A missing trailing slash on the source produces dst/src instead of filling dst. Preview with -n if you are unsure.
  • Backing up a home folder with *. rsync -a /home/peter/* dst/ silently drops every top-level dotfile (.bashrc, .ssh, .config), because the shell expands the * and never matches hidden names. Use the trailing-slash form /home/peter/ instead.
  • Running --delete with a typo. If the source path is wrong or empty, --delete can strip the destination bare. Dry-run first, always.
  • Forgetting -a and using bare -r. Without preserved times and permissions, the next sync copies everything again and the files arrive with the wrong ownership.
  • Compressing already-compressed data. Adding -z to a transfer of videos or ZIP files wastes CPU for almost no saving. Save -z for text and code over the network.
  • Trusting a same-disk sync as a backup. If the disk fails, source and destination go together. A real backup lives on separate storage, ideally off-site.
Back to top

10. Summary

The rsync command looks like a fancier cp, but it is really a small synchronisation engine that happens to fit on one command line.

  • rsync means "remote sync". It makes a destination match a source and transfers only what changed, which is why repeated syncs are fast.
  • It dates from 1996 and carries a differencing algorithm and a network protocol inside a single tool.
  • The last argument is the destination. A trailing slash on the source (src/) copies the contents; no slash (src) copies the folder itself. Prefer src/ over src/*, or the shell drops your hidden dotfiles.
  • -a (archive) is the everyday flag: it means -rlptgoD, so it copies recursively and keeps links, permissions, times, and ownership.
  • Add -z to compress remote transfers, -P to resume and show progress, and -e "ssh ..." to control the SSH connection.
  • --delete turns a copy into a true mirror by removing files that no longer exist at the source. Preview it with -avn every time.
  • --exclude skips unwanted files; -A, -X, and -H add ACLs, extended attributes, and hard links for a faithful system copy.
  • The delta-transfer algorithm sends only the changed pieces of a file over the network, and --link-dest builds space-efficient snapshot backups with hard links.
  • Beyond SSH, rsync can talk to a daemon (host::module, port 873) for public mirrors, and --inplace with -S updates large or sparse files efficiently.
  • Know where rsync stops: cp and scp for one-off copies, tar for archives, git for history, dd for whole disks, and borg, rclone, or Syncthing for deduplicated, cloud, or two-way sync.
  • When in doubt, type man rsync.

This is the quick reference worth keeping:

rsync -a src/ dst/              sync contents of src into dst
rsync -a src  dst/             copy the folder src into dst (dst/src)
rsync -avn src/ dst/           dry run: show what would change
rsync -aP big.iso host:/data/  resume-friendly copy with progress
rsync -a --info=progress2 s/ d/  one overall progress bar for the whole job
rsync -az src/ user@host:/dst/ compressed copy over SSH
rsync -a --delete src/ dst/    mirror: also remove extra files in dst
rsync -a --exclude '*.log' s/ d/   skip files matching a pattern
rsync -aAXH src/ dst/          faithful copy with ACLs, xattrs, hard links
rsync -a --link-dest=/prev src/ /new/   space-saving snapshot backup

Small commands like rsync quietly hold up serious infrastructure: the backups that run every night, the deployments that push a website live, the migration that moves a business to a new server. If your servers matter and you want them backed up, deployed, and maintained by someone who understands what is really happening underneath, that is exactly the kind of work I enjoy helping with.

Back to top
Linux command: rsync
Peter Martin
Peter Martin
Joomla Specialist

Peter is a Joomla specialist and a Linux admin for fast, secure and scalable websites.