Moving files to a server from a Mac
File transfer on a Mac is one of those tasks that looks solved until the file gets large, the connection drops, or the filenames contain anything other than plain ASCII. Then the Finder window that has worked for years starts throwing errors halfway through, a copied folder arrives with .DS_Store scattered through it, and a command lifted from a tutorial fails with an unrecognized option.
The reason is that macOS ships a specific and slightly unusual set of transfer tools, and most advice on the subject was written for Linux. Knowing exactly what is on the machine, and which of the three or four routes actually fits the job, removes almost all of the guesswork.
What macOS actually ships
Every current Mac already has what it needs for server transfers. There is no package to install for the common cases.
OpenSSH is included, which covers ssh, scp, and sftp. That matters more than it used to, because the behaviour of scp changed. As of OpenSSH 9.0, released in April 2022, the command no longer uses its own legacy protocol.
This release switches scp(1) from using the legacy scp/rcp protocol to using the SFTP protocol by default. Source: openssh.com
In practice this means scp and sftp now do the same thing underneath, and the old advice about quoting shell metacharacters twice for remote paths no longer applies in the same way. It also means a scp command that worked against an old embedded device may now need the -O flag to fall back to the legacy protocol.
curl is present and speaks HTTP, HTTPS, FTP, FTPS, and SFTP. nc, smbutil, and mount_smbfs are all there. What is not there is a plain ftp command: Apple removed the ftp and telnet clients in macOS High Sierra, so anything that still needs FTP has to go through curl, Finder, or a third party client.
rsync is present, and this is where the surprises start.
The bundled rsync is not the rsync in the tutorials
For many years macOS shipped rsync 2.6.9, a build from 2006 kept at that version for licensing reasons. macOS 15 replaced it with openrsync, a separate implementation that reports itself as compatible with the old version. On a current system, rsync --version prints a protocol version of 29 and the line rsync version 2.6.9 compatible.
Compatible does not mean identical. Several options that appear in nearly every rsync guide are simply not implemented:
| Option | Purpose | In macOS openrsync |
|---|---|---|
--iconv |
Convert filename encoding between hosts | Not available |
-X, --xattrs |
Copy extended attributes | Not available, --extended-attributes exists |
-A, --acls |
Copy access control lists | Not available |
--partial |
Keep partially transferred files | Available |
--exclude |
Skip matching paths | Available |
-z, --compress |
Compress during transfer | Available |
The missing --iconv is the one that causes real damage. macOS stores filenames in decomposed Unicode form, while Linux servers almost always store them composed. A folder name with an accented character or Japanese text can arrive on the server looking correct but comparing as a different string, which produces duplicate directories on the next sync. GNU rsync solves this with --iconv=UTF-8-MAC,UTF-8. The bundled openrsync cannot, and answers with unrecognized option.
If filenames go beyond ASCII, install GNU rsync through a package manager and call it explicitly rather than relying on rsync in the path. For pure ASCII paths, the bundled version is fine and one less dependency.
Two more macOS specific habits are worth building in. Add --exclude='.DS_Store' so Finder metadata stops accumulating on the server, and be aware that copying to a non Apple file system can leave ._name companion files holding resource forks. Setting COPYFILE_DISABLE=1 before a tar run suppresses those.
Finder, and the point where it stops
Finder handles the graphical half through Go, then Connect to Server, or Command K. It speaks smb://, afp://, nfs://, ftp://, and http(s):// for WebDAV. SMB has been the default for Mac to Mac and Mac to server sharing since OS X Mavericks, and AFP is legacy at this point.
For occasional access to a shared drive, this is the right tool and needs no further thought. Three limits appear once transfers become routine.
Finder mounts FTP read only, so uploads are impossible through that route. Interrupted copies of large files generally restart from zero rather than resuming. And a mounted network volume is treated like a local disk, which means Spotlight indexing, thumbnail generation, and folder size calculation can all fire across the network and make the mount feel unusable.
There is also no memory between sessions. Every mount is a fresh dialog with a fresh path. That is tolerable weekly and grating hourly.
Choosing a route
| Route | Best for | Resumes | Preserves permissions | Scriptable |
|---|---|---|---|---|
| AirDrop | One file to a nearby Apple device | No | No | No |
| Finder, Connect to Server | Occasional browsing of a share | No | Partly | No |
scp |
A single file or small folder, once | No | With -p |
Yes |
sftp |
Interactive poking around a remote tree | With reget |
Partly | Awkward |
rsync over SSH |
Repeated transfers of a changing tree | With --partial |
With -a |
Yes |
| Mounted SFTP volume | Editing remote files in a local app | Not applicable | Depends | Partly |
The dividing line is repetition. A transfer that happens once is a scp job and thinking about it further is wasted effort. A transfer that happens every day is an rsync job, because only rsync skips what has not changed, and that difference grows with the size of the tree.
Mounting a remote filesystem locally sits in its own category. On macOS this needs a third party layer such as macFUSE with sshfs, or a commercial client such as Mountain Duck or ForkLift. It is excellent for editing a handful of remote files in a local editor and poor for anything that reads many files quickly, because every read is a round trip.
Making the repeat case cheap
Most of the friction in daily transfers is not the transfer. It is the typing around it.
An ~/.ssh/config entry turns a long connection string into a word:
Host web
HostName 203.0.113.10
User deploy
IdentityFile ~/.ssh/id_ed25519
ControlMaster auto
ControlPath ~/.ssh/cm-%r@%h:%p
ControlPersist 10m
After that, ssh web and rsync -av ./dist/ web:/var/www/site/ both work, and the ControlPersist lines reuse a single authenticated connection for ten minutes so repeated commands do not each pay for a new handshake.
Three habits prevent most accidents. Run the command with -n first, which lists what would move without moving it. Understand that a trailing slash on the source means the contents of the directory while no trailing slash means the directory itself, which is the single most common cause of a nested site/site/ on a server. And add --partial --progress for anything large, so a dropped connection resumes instead of restarting.
For verification after the fact, compare hashes rather than trusting file sizes. shasum -a 256 file on both ends is definitive, and rsync's own -c flag forces a checksum comparison at the cost of reading everything twice.
What the files look like when they land
A transfer that completes is not the same as a transfer that worked. The most common failure after a clean run is a permission problem on the far side, and it comes from a small piece of rsync behaviour that is easy to miss.
The -a flag is a bundle. It implies recursion plus preservation of symlinks, permissions, modification times, and group and owner. Preserving owner requires being root on the receiving end, so a transfer as an ordinary user quietly drops that part and the files arrive owned by the connecting account. On a web server that usually means a directory full of content the service account cannot read, and a deploy that looks successful but returns a 403.
There are two clean answers. Set the mode explicitly during transfer with --chmod=D755,F644, which stops local permissions from leaking outward and produces predictable results regardless of the source machine. Or transfer into a staging directory and let a step on the server move the files into place with the correct ownership. Which one fits depends on whether the connecting account has the rights to do the second, but picking one deliberately beats discovering the problem from a browser.
Timestamps deserve a moment too. Without -t, rsync cannot use modification times to decide what changed, so every subsequent run compares content instead and the whole point of using rsync disappears. -a includes -t, which is a good reason to prefer it over assembling flags individually.
Large files on a connection that drops
A multi gigabyte file over a link that dies every twenty minutes is the case that turns a five minute task into an afternoon, and it is entirely avoidable.
--partial keeps whatever arrived instead of deleting it, so the next run resumes. --append goes further and assumes the destination is a prefix of the source, which is fast but only safe when the source file has not been modified between attempts. Pairing --partial with --progress, or simply using -P, gives both the resume behaviour and a visible transfer rate, which is the quickest way to tell a slow link apart from a stalled one.
Two related habits help. Setting --bwlimit keeps a large upload from saturating the connection and making everything else on the network unusable, which matters when the transfer runs during working hours. And for an archive of many small files, compressing into a single stream first tends to beat sending them individually, because per file overhead dominates once the files are small enough.
For a one off delivery of a very large file where SSH is not available, curl uploading to a signed URL is often the shortest path, and it accepts -C - to continue an interrupted upload.
The window count problem
Look at what a routine deploy or delivery actually involves on a Mac. A Finder window to locate and stage the files. A terminal window to run the transfer and check the result on the far end. Frequently a third window holding an assistant that is being asked how to phrase the rsync flags, without any knowledge of which directory is currently selected or what the server looks like.
Each of those windows has its own idea of the current directory, and reconciling them by hand is the actual overhead. It rarely shows up as a complaint about file transfer, because it feels like normal work. It is still the largest single cost in the loop.
A file manager where the shell inherits the visible folder removes half of it. One where an assistant reads the same working directory removes most of the rest, because the question stops being asked in the abstract and starts being asked about the files on screen. The behaviours involved are described under what it does, how a transfer that is still running is checked away from the desk is covered under continuing from iPhone and iPad, and a side by side view against other tools sits on the comparison page.
What to change first
Write one ~/.ssh/config entry for the server used most often, with ControlPersist enabled, and switch the daily copy from scp to rsync -av --partial --progress. That takes about ten minutes and removes the retyping, the full restarts, and most of the wrong destination mistakes. If what remains is jumping between a folder, a shell, and an assistant that cannot see either, the tool to look at next is Atriens, which keeps the three in one window.
Frequently asked questions
Does macOS come with rsync, and is it the same as the one on Linux?
It comes with rsync, but since macOS 15 it is openrsync, which reports itself as compatible with rsync 2.6.9. Common flags such as -a, --partial, --exclude, and --delete work. Options including --iconv, -X, and -A are not implemented, so scripts written against GNU rsync may fail with an unrecognized option error.
Why do transferred filenames with accents or Japanese characters end up duplicated on the server?
macOS stores filenames in decomposed Unicode while most Linux servers store them composed, so the same visible name is a different byte sequence on each side. GNU rsync fixes this with --iconv=UTF-8-MAC,UTF-8. The bundled openrsync does not support that flag, so installing GNU rsync separately is the practical answer.
Is scp still safe to use, or has it been replaced?
It is still shipped and still encrypted. Since OpenSSH 9.0 it uses the SFTP protocol underneath rather than the old scp/rcp protocol, which removed a class of quoting problems. Older servers or embedded devices that only speak the legacy protocol may need the -O flag. For anything transferred more than once, rsync is the better choice because it skips unchanged files.
Can Finder upload to an FTP server?
No. Finder mounts FTP shares read only, so browsing and downloading work but uploading does not. macOS also removed the command line ftp client in High Sierra. Uploading over FTP now requires curl -T, or a third party client such as Cyberduck or FileZilla. Where the server supports it, SFTP over SSH is the better route.