skip to content

A release script pushes a 4 GB build directory to each server with `scp -r`, and almost nothing changes between releases. What does rsync do differently that makes it the better tool for this, and what changed about scp itself in OpenSSH 9.0?

level: juniorimportance: nice to knowfreq 45%

answer

  1. one tool knows the destination, one does not
  2. 4 GB versus a few changed blocks
  3. what happens when the link drops
  4. the far side needs the same binary
  5. OpenSSH 9.0 changed the wire protocol

basics

~20 s

rsync compares source and destination and sends only what differs, can resume an interrupted run and can prune removed files, so a mostly-unchanged 4 GB tree costs seconds; scp re-sends every byte every time. Since OpenSSH 9.0 scp uses the SFTP protocol internally.

solid answer

~50 s

`scp -r` is a plain copy: it has no idea what is already on the far end, so it re-sends all 4 GB every release, and if the link drops halfway you start again. rsync builds a file list on both sides, skips files whose size and modification time already match, and for files that did change sends only the differing blocks — then `--delete` can remove files that no longer exist in the build. `rsync -az --delete build/ host:/srv/app/` over SSH is the drop-in replacement; use `-e 'ssh -p 2222'` if the port is non-standard, and remember rsync must be installed on **both** hosts, since it starts a peer process on the remote. On scp itself: OpenSSH 9.0 switched it to use the SFTP protocol rather than the legacy rcp-derived one, because the old protocol left too much filename handling to the client; `-O` forces the legacy behaviour for servers that need it.

go deeper

for a junior

Be able to state the core contrast without hesitation: scp copies everything every time, rsync copies only differences and can resume. Naming rsync -a over SSH as the replacement for scp -r is enough at this level.

for a middle

Explain the two layers of saving — the size-plus-mtime quick check that skips whole files, and the block-level delta for files that did change — and note that rsync needs a peer binary on the remote host.

for a senior

Bring judgement: when the comparison cost exceeds the network saving, why -z can be a pessimisation, and the fact that neither tool gives you an atomic release, so a deploy needs a staging directory and a swap.

for a principal

Own the standard. Decide whether release artefacts should be pushed at all versus pulled from an artefact store or shipped as images, and what that choice implies for reproducibility, auditability and rollback across a fleet.

## What each tool actually is `scp` is a file *copier* that happens to run over SSH. It takes paths, opens them, and streams bytes. It carries no model of the destination's current state, so every invocation is a full copy. `rsync` is a file *synchroniser*. It starts a peer process on the far end, the two sides exchange file lists and metadata, and rsync transfers only what is needed to make the destination match the source. That difference is the whole answer to the question. ## Concretely, for a 4 GB release directory ``` scp -r build/ host:/srv/app/ # ~4 GB on the wire, every time rsync -az --delete build/ host:/srv/app/ # only what changed ``` rsync's savings come in two layers: 1. **File selection.** By default rsync skips any file whose size *and* modification time already match on the destination — its "quick check". For a build where only a handful of artefacts were rebuilt, most files are never opened for transfer at all. 2. **Within-file deltas.** For a file that did change, rsync's delta-transfer algorithm sends only the differing blocks plus references to the blocks the receiver already holds, instead of the whole file. On top of that you get things scp simply does not have: `--delete` to remove files that vanished from the build, `--partial`/`-P` so an interrupted run resumes rather than restarting the largest file, `--bwlimit` to stay off the edge of the link, `-a` to preserve permissions and timestamps, `--exclude` patterns, and `-n` to see what a run would do first. ## What rsync costs you - **rsync must exist on both hosts.** Over SSH, rsync logs in and runs `rsync --server` on the far side; if the remote does not have the binary the command fails. `scp` and `sftp` need only a working `sshd`. `--rsync-path=` lets you point at a non-default binary path. - **Both sides do work.** The comparison reads metadata for every file, and delta transfer reads file contents on both ends. On a huge tree over a fast local link, that CPU and disk cost can exceed the network saving — which is exactly why rsync defaults to `--whole-file` when both paths are local. - **`-z` is not free.** Compressing already-compressed artefacts (jars, images, zips) burns CPU for nothing. Modern rsync can negotiate a cheaper algorithm; `--compress-choice=` (`--zc`) selects one explicitly, and `--skip-compress=` lists suffixes to leave alone. ## The scp change in OpenSSH 9.0 Historically `scp` spoke a protocol inherited from `rcp`: the client asked for a path, and the *server* replied with a stream of filenames, sizes and modes that the client wrote out. The client was expected to police what came back, and that trust boundary produced a series of problems — a malicious or compromised server could return names the client had not asked for, and wildcard expansion happened in a remote shell. OpenSSH 9.0 changed `scp` to use the **SFTP protocol** by default. The command-line interface is unchanged, but the wire protocol is now the same well-specified one `sftp` uses. Practical consequences worth knowing: - Remote wildcards are handled differently, because there is no remote shell expanding the pattern the old way. - Some paths that worked under the legacy protocol need `-O` (the flag that forces the legacy scp/rcp protocol) against older or non-standard servers. - OpenSSH's own guidance treats scp as a legacy interface: for scripted transfers, prefer `sftp` for simple copies and `rsync` for synchronisation. ## Choosing, in practice - One file, once, interactively: `scp` or `sftp` is fine and requires nothing on the far side. - A directory tree you will push repeatedly, or anything where restartability, deletion or metadata fidelity matters: rsync. - A release artefact that must appear atomically: neither tool is atomic on its own — rsync into a staging directory and swap a symlink, or use `--delay-updates` so the renames happen at the end.

  • Why does the remote host need rsync installed, when scp only needs sshd?
    rsync is a two-process protocol. Over SSH it logs in and executes `rsync --server` on the far side; the two peers then exchange file lists and checksums. Without a remote binary there is nobody to compute the destination's block checksums, so there can be no delta transfer. `scp` and `sftp` are served by sshd's own subsystem, so no extra software is needed.
  • When would you deliberately keep using scp or sftp instead of rsync?
    When the far side does not and cannot have rsync installed, when the transfer is a single file copied once so the comparison work buys nothing, or when a restricted environment only exposes sshd's SFTP subsystem. For one-shot interactive copies the simpler tool is also less to get wrong — the case for rsync is repetition.
  • Is `-z` always worth adding to an rsync-over-SSH push?
    No. It costs CPU on both ends and gains nothing on already-compressed data such as archives, images or media — on a fast link it can be slower than sending raw bytes. It pays on text-heavy trees over a constrained link. Use `--skip-compress=` for suffixes that should be left alone, and `--compress-choice=` to pick a cheaper algorithm.

saying these in an interview costs you the question

  • Claims scp resumes an interrupted transfer
  • Thinks rsync works with only sshd on the remote host
  • Says rsync is always faster, including local disk-to-disk
  • Adds -z reflexively to already-compressed artefacts
  • Believes scp can delete files removed from the source

context