Blog
3 min read

scp vs rsync: How to Copy Files to and From a Server

scp copies files over SSH simply; rsync copies only what changed, can resume, and can mirror folders. Examples for uploading and downloading files and folders with each, the trailing-slash rule, --delete, excluding files, and when to use sftp or Git instead.

You've got a server, and you need to move files to it (a build, a config file, a database dump) or from it (logs, a backup). The two classic tools are scp and rsync. Both use SSH, so if you can ssh into the server, you can use them. (How to SSH into a server)

scp: simple copying

scp works like cp, but one side can be a remote machine (user@host:path).

# upload a file
scp backup.sql deploy@203.0.113.10:/home/deploy/

# download a file
scp deploy@203.0.113.10:/var/log/app.log ./

# upload a folder (recursive)
scp -r ./dist deploy@203.0.113.10:/srv/myapp/

# non-standard SSH port
scp -P 2222 file.txt deploy@203.0.113.10:~/

If you've set up an SSH config entry, use its name: scp file.txt myserver:~/. (The SSH config file)

Good for: one-off copies of a file or small folder.

Limits: copies everything every time, can't resume an interrupted transfer, no way to skip unchanged files.

rsync: smart syncing

rsync compares source and destination and only transfers what's different. For a folder with thousands of files where three changed, it sends three.

# sync a folder to the server
rsync -avz ./dist/ deploy@203.0.113.10:/srv/myapp/dist/

# download a folder
rsync -avz deploy@203.0.113.10:/srv/myapp/uploads/ ./uploads/

# see what WOULD happen, without doing it
rsync -avz --dry-run ./dist/ myserver:/srv/myapp/dist/

Flags you'll use:

Flag Meaning
-a Archive: recursive, keep permissions, times, symlinks
-v Verbose — list files
-z Compress during transfer
-P Show progress and keep partial files (resume big transfers)
-n / --dry-run Show what would change
--delete Delete files at the destination that no longer exist at the source
--exclude Skip matching files

The trailing slash matters

rsync -a dist/  server:/srv/app/dist/   # copies the CONTENTS of dist into dist
rsync -a dist   server:/srv/app/        # copies the FOLDER dist into app/

Leave it off when you meant to include it and you get dist/dist/. When in doubt, --dry-run first.

Mirroring with --delete

rsync -avz --delete ./dist/ myserver:/srv/myapp/dist/

Makes the destination an exact copy, removing old files. Powerful — and destructive if you point it at the wrong folder. Always dry-run --delete the first time.

Excluding files

rsync -avz --exclude node_modules --exclude .git --exclude .env ./ myserver:/srv/myapp/

Side by side

scp rsync
Copies only changes No Yes
Resume interrupted transfers No Yes (-P)
Mirror and delete extras No Yes (--delete)
Exclude patterns No Yes
Needs installing on the server No (uses SSH) Usually pre-installed; needed on both ends
Simplicity Very simple More options

Rule of thumb: a file or two → scp. A folder you'll update repeatedly, or anything large → rsync.

Other ways

  • sftp — an interactive file-transfer session over SSH (sftp myserver, then put/get). GUI clients like FileZilla, Cyberduck and WinSCP use it.
  • VS Code Remote SSH — drag and drop files in the editor. (VS Code Remote SSH)
  • Git — for code, push to a repository and pull on the server (or deploy via CI) instead of copying files by hand. It's repeatable and gives you history. (Deploy to a VPS with GitHub Actions)

Never copy secrets carelessly

.env files and database dumps contain sensitive data. Copy them over SSH (scp/rsync are encrypted), don't leave copies lying in /tmp or your Downloads folder, and never commit them. (Secrets management)


EasySpawn deploys your code from Git and gives you SSH access when you do need to move files by hand — with backups in place before you --delete anything. See how it works or join the waitlist.

Related: How to SSH Into a Server · The SSH Config File Explained · Basic Linux Commands · Deploy a Node.js App to a VPS

Keep reading