Exclude and Include Patterns
Rsync's filter system lets you precisely control which files are transferred. Without filters, rsync copies everything — including cache directories, log files, temporary uploads, and development artifacts that have no place in a backup or deployment.
Basic Exclude
Exclude a Single Directory
rsync -av --exclude='cache/' /var/www/html/ /backup/www/
Exclude Multiple Patterns
rsync -av \
--exclude='cache/' \
--exclude='*.log' \
--exclude='*.tmp' \
--exclude='.git/' \
--exclude='node_modules/' \
/var/www/html/ /backup/www/
Exclude by File Extension
# Skip all log files and temporary files
rsync -av --exclude='*.log' --exclude='*.tmp' --exclude='*.swp' \
/var/www/ /backup/
Basic Include
Include Only Specific File Types
When you want to sync only certain files, use include + exclude together:
# Sync only PHP files
rsync -av \
--include='*/' \
--include='*.php' \
--exclude='*' \
/var/www/html/ /backup/php-only/
The --include='*/' must come first — it tells rsync to traverse all directories. Without it, rsync won't descend into subdirectories to find matching files. The final --exclude='*' blocks everything not explicitly included.
Include Multiple File Types
# Sync only code files
rsync -av \
--include='*/' \
--include='*.php' \
--include='*.js' \
--include='*.css' \
--include='*.html' \
--exclude='*' \
/var/www/html/ /backup/code-only/
Pattern Matching Rules
| Pattern | Matches | Example |
|---|---|---|
*.log | Any file ending in .log at any depth | error.log, app/debug.log |
cache/ | Any directory named cache at any depth | wp-content/cache/, app/cache/ |
/cache/ | Only cache/ at the root of the transfer | Root cache/ only, not sub/cache/ |
*.jpg | All JPEG files anywhere | All .jpg files |
backup* | Files/dirs starting with backup | backup.sql, backup-2024/ |
**/*.log | Any .log file in any subdirectory | Same as *.log (rsync default) |
Anchored vs Unanchored Patterns
# Unanchored — matches 'cache/' anywhere in the tree
--exclude='cache/'
# Matches: /var/www/html/wp-content/cache/
# Matches: /var/www/html/app/tmp/cache/
# Anchored (leading /) — matches only at the transfer root
--exclude='/cache/'
# Matches: /var/www/html/cache/ (root level only)
# Skips: /var/www/html/wp-content/cache/
Using Exclude Files
For complex projects, put rules in a file instead of the command line:
# Development artifacts
.git/
node_modules/
.env
*.map
# Caches and temporary files
cache/
tmp/
*.tmp
*.log
*.swp
# OS junk
.DS_Store
Thumbs.db
# Build artifacts
dist/
build/
vendor/
rsync -av --exclude-from='rsync-exclude.txt' \
/var/www/html/ user@backup:/backups/www/
Store rsync-exclude.txt in your project root or /etc/rsync/. This makes filters version-controlled and reusable across team members and servers.
Using .gitignore as Filter
If your project already has a .gitignore, you can use it directly:
rsync -av --filter=':- .gitignore' \
/var/www/html/ user@server:/deploy/www/
This reads each directory's .gitignore file and applies those rules. Perfect for deploying from a Git repository without sending development artifacts.
Common Filter Recipes
Web Application Deployment
rsync -avz \
--exclude='.git/' \
--exclude='node_modules/' \
--exclude='.env' \
--exclude='*.map' \
--exclude='tests/' \
--exclude='*.test.js' \
--exclude='*.spec.js' \
/var/www/app/ user@production:/var/www/app/
PHP Application Backup (WordPress Example)
rsync -avz \
--exclude='wp-content/cache/' \
--exclude='storage/framework/cache/' \
--exclude='var/cache/' \
--exclude='*.log' \
--exclude='.env' \
/var/www/html/ /backup/app-files/
Config Files Only
rsync -av \
--include='*/' \
--include='*.conf' \
--include='*.cfg' \
--include='*.ini' \
--include='*.yml' \
--include='*.yaml' \
--include='*.toml' \
--exclude='*' \
/etc/ /backup/configs/
Sync Everything Except Large Media
rsync -avz \
--exclude='*.mp4' \
--exclude='*.mov' \
--exclude='*.avi' \
--exclude='*.zip' \
--exclude='*.tar.gz' \
/var/www/html/ user@remote:/backup/
Testing Patterns with Dry Run
Always test your patterns before running on production:
# Preview what will be included/excluded
rsync -av --dry-run \
--exclude='cache/' \
--exclude='*.log' \
/var/www/html/ /backup/www/
# See detailed per-file decisions
rsync -av --dry-run --itemize-changes \
--exclude='cache/' \
/var/www/html/ /backup/www/
Common Pitfalls
| Pitfall | What Happens | Fix |
|---|---|---|
--exclude before --include | Files excluded before include rule is evaluated | Put --include rules first |
Missing --include='*/' | Rsync doesn't traverse subdirectories | Always include */ when filtering by file type |
No trailing / on directory excludes | May match files with similar names | Use cache/ not cache for directories |
| Anchored pattern when you want recursive | Only matches at root level | Remove leading / for recursive matching |
Not testing with --dry-run | Wrong files excluded/included in production | Always preview first |
Shell expansion of * | Shell expands * before rsync sees it | Always quote patterns: '*.log' not *.log |
Quick Reference
# Exclude a directory
rsync -av --exclude='cache/' /src/ /dest/
# Exclude multiple patterns
rsync -av --exclude='*.log' --exclude='*.tmp' /src/ /dest/
# Include only PHP files
rsync -av --include='*/' --include='*.php' --exclude='*' /src/ /dest/
# Use exclude file
rsync -av --exclude-from='rsync-exclude.txt' /src/ /dest/
# Use .gitignore rules
rsync -av --filter=':- .gitignore' /src/ /dest/
# Test patterns before running
rsync -av --dry-run --exclude='cache/' /src/ /dest/
What's Next
- Handling Deleted Files — Control how rsync manages deletions
- Dry Run and Testing — Validate commands before execution
- Operators and Keywords — Advanced wildcard patterns