Applies to: rsync 3.5.0 (Debian 13, AlmaLinux 10.2) and rsync 3.2.7 (Ubuntu 24.04)
To make rsync skip files or folders, add --exclude with a pattern, once per pattern:
rsync -av --exclude='cache/' --exclude='*.log' /var/www/site/ /backup/site/
Three things decide whether an exclude works: the pattern is matched against paths relative to the folder you copy (never the full path on disk), a trailing / means "directories only", and a leading / means "only at the top of the transfer". For many patterns, put them in a file and use --exclude-from. Always test with a dry run (-n) first.
Quick reference
--exclude='cache/': every folder namedcache, at any depth, with its contents.--exclude='cache': every file or folder namedcache.--exclude='/cache/': only thecachefolder directly inside the source.--exclude='wp-content/cache/': only that nested folder.--exclude='cache/*': the contents ofcache, but the empty folder is still created.--exclude='*.log': all files ending in.log.--exclude='.*': all hidden files and folders (.git,.env,.htaccess).--exclude='my notes.txt': a name with spaces, in quotes.
We tested every pattern below on this lab folder:
site/.env site/.git/HEAD site/assets/cache (a file, not a folder) site/cache/page.html site/error.log site/index.php site/logs/access.log site/logs/keep.log site/node_modules/pkg/index.js site/wp-content/cache/x.html site/wp-content/uploads/2026/photo.jpg
Exclude a folder (and get the path right)
- Write the pattern relative to the source. With
site/as the source,site/cacheis/cacheorcachein rsync terms. A full path does not match:--exclude='/tmp/lab/site/cache'excluded nothing in our test. - Add a trailing
/if you only mean folders. In the lab,--exclude='cache'also skipped the fileassets/cache;--exclude='cache/'copied it and skipped only the two folders. - Add a leading
/if you only mean the top level.--exclude='/cache/'skippedsite/cachebut still copiedwp-content/cache. - Watch the trailing slash on the source. Without it (
rsync -a site /backup/) the folder name becomes part of every path, so/cache/matched nothing and we needed/site/cache/instead. See how to use rsync to copy and sync folders for what the trailing slash does.
A pattern with a slash in the middle, such as wp-content/cache, has to match whole path parts: content/cache did not exclude wp-content/cache. Use ** to match any number of folders, for example --exclude='wp-content/**/2026' skipped wp-content/uploads/2026.
Exclude several files and folders
- Repeat the option:
--exclude='*.log' --exclude='node_modules/' --exclude='.git/'. Each--excludetakes exactly one pattern. - In Bash you can shorten that with braces,
--exclude={'*.log','node_modules','.git'}, because Bash expands it into three options. This does not work inshon Debian and Ubuntu (dash), and cron runs jobs withshunless the crontab setsSHELL: in our test undershnothing was excluded. Use separate options or a file in scripts and cron jobs. - Use an exclude file for longer lists. Blank lines and lines starting with
#or;are ignored:$ cat exclude.txt # build and cache files *.log cache/ node_modules/ .git/ .env $ rsync -a --exclude-from=exclude.txt site/ /backup/site/
Do not leave spaces at the end of a line: in our test a linecache/(with a trailing space) excluded nothing.
Preview and debug with a dry run
- Add
-n(--dry-run) and-vto see what would be copied without copying anything. Lab example:$ rsync -avn --exclude-from=exclude.txt site/ dst/ sending incremental file list created directory dst ./ config.php index.php my notes.txt assets/ assets/app.js assets/cache logs/ wp-content/ wp-content/uploads/ wp-content/uploads/2026/ wp-content/uploads/2026/photo.jpg ... total size is 12 speedup is 0.03 (DRY RUN)
- Add
--debug=FILTERto see which rule skipped each item:$ rsync -an --debug=FILTER --exclude='cache/' --exclude='*.log' site/ dst/ [sender] hiding directory cache because of pattern cache/ [sender] hiding file error.log because of pattern *.log [sender] hiding file logs/keep.log because of pattern *.log [sender] hiding file logs/access.log because of pattern *.log [sender] hiding directory wp-content/cache because of pattern cache/
For rules read from--exclude-from, rsync 3.5.0 printed "because of pattern <rule from a file read earlier>" instead of the pattern. - Remove
-nand run the real copy.
Include some files and exclude the rest
rsync checks the rules in order and the first rule that matches wins, so put --include before the --exclude it should override.
- Copy only PHP files and keep the folder structure:
rsync -am --include='*/' --include='*.php' --exclude='*' site/ /backup/php/
--include='*/'lets rsync walk into every folder, and-m(--prune-empty-dirs) drops the folders that end up empty. Without-mour copy had ten empty folders; with the order reversed (--exclude='*'first) it copied nothing at all. - Skip a folder's contents but keep one file:
rsync -a --include='logs/keep.log' --exclude='logs/*' site/ /backup/site/
This copied onlylogs/keep.log. With--exclude='logs/'instead, nothing inlogswas copied, because rsync never looks inside an excluded folder.
Excludes and --delete
With --delete, rsync removes files from the destination that are gone from the source, but it does not delete excluded files there: in our test dst/cache survived --delete --exclude='cache/'. Add --delete-excluded if the destination should lose them too. Our run then printed:
deleting cache/page.html deleting cache/ deleting index.php ./ deleting wp-content/cache/x.html deleting wp-content/cache/
Run any --delete command with -n first.
Excludes over SSH, .gitignore and -C
- Remote copies use exactly the same patterns, still relative to the source folder:
rsync -av --exclude='cache/' /var/www/site/ user@server:/backup/site/. For a custom SSH port, see rsync with a non-standard SSH port. --filter=':- .gitignore'reads exclude patterns from.gitignorefiles in each folder. It skippednode_modulesand the log files in our test. rsync reads the file with its own rules, not Git's, so keep it to simple patterns.-C(--cvs-exclude) skips.git/,.svn/and similar folders, but its built-in list also containscore,*.so,*.exe,*.bakand*.old, according to the rsync manual. Do not use it for full server or website backups.
"skipping directory" message
If rsync prints skipping directory site and copies nothing, you forgot -r or -a. Without one of them rsync does not copy folders. It still exits with code 0 in our test, so a script will not notice. Add -a (archive mode, which includes -r).
Related articles: how to use rsync to copy and sync files and directories, how to rsync only new or changed files, how to copy a folder recursively with scp and exclude files, 13 rsync command examples.