Skip to content
Latchkey

gsutil rsync -r: Mirror Directories to GCS

gsutil rsync -r makes a GCS bucket match a local directory, transferring only differences and, with -d, deleting objects not present at the source.

rsync is gsutil incremental sync: it skips unchanged files, which makes repeated cache and site deploys cheap. -r recurses, -d deletes to produce an exact mirror, and -m parallelizes.

What it does

gsutil rsync compares source and destination and copies only the differences. -r makes it recursive. -d deletes destination objects that are not in the source (exact mirror). By default it compares size and, when available, checksums.

Common usage

Terminal
gsutil -m rsync -r ./dist gs://my-bucket/site
# exact mirror: delete removed files too
gsutil -m rsync -r -d ./public gs://my-bucket/www
# force checksum comparison instead of mtime/size
gsutil -m rsync -r -c ./data gs://my-bucket/data

Options

FlagWhat it does
-rRecurse into subdirectories
-dDelete destination objects not present in the source
-cCompare checksums, not just size and mtime
-x <pattern>Exclude paths matching the regex
-nDry run: show actions without performing them

In CI

Combine -m for parallelism with -d for static-site deploys so removed pages are purged. -d is destructive: confirm the direction (local source then gs:// destination) and consider -n first. Because rsync skips unchanged objects, it is far cheaper than a full cp on repeated runs.

Common errors in CI

"AccessDeniedException: 403" on a run with -d means the identity lacks storage.objects.delete; -d needs delete permission. "CommandException: Caught non-retryable exception" often wraps a 403 or a 404 BucketNotFoundException. "ServiceException: 401 Anonymous caller does not have storage.objects.list access" means credentials did not resolve.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →