rsync exclude hidden files Mac is a useful search because hidden files are where many developer backups go wrong. Dotfiles can be essential project configuration, disposable cache, private secret, Git history, macOS metadata, or tool state. A safe backup does not blindly copy every hidden path, and it also does not blindly delete every path that starts with a dot.
rsync exclude hidden files Mac: the safe starting point
The common shortcut is this:
rsync -avhn --exclude='.*' ~/Developer/my-app/ /Volumes/DevBackup/my-app/
That command is attractive because it appears to skip hidden files and hidden folders in one rule. It is also too blunt for most code projects. It excludes .gitignore, .npmrc, .ruby-version, .python-version, .tool-versions, .editorconfig, .env.example, and any other dotfile that may define how the project should build on a new machine.
Use a dry run first. The n in -avhn means no changes are made. It gives you a chance to catch missing config before the real copy:
rsync -avhn --itemize-changes \
--exclude='.DS_Store' \
--exclude='.Spotlight-V100/' \
--exclude='.Trashes/' \
--exclude='.fseventsd/' \
~/Developer/my-app/ /Volumes/DevBackup/my-app/
That smaller starter set skips macOS volume metadata without removing project configuration. From there, add explicit developer-tool folders that are safe to regenerate: node_modules/, .venv/, .pytest_cache/, .next/cache/, .turbo/, coverage/, dist/, and build/.
Why hidden files are risky in developer backups
macOS hides files whose names start with a dot because the convention comes from Unix. Developer tooling leans heavily on that convention. A project root might include visible folders such as src and tests, but the real build recipe often lives in hidden files.
- Keep most project config. Files such as
.editorconfig,.nvmrc,.node-version,.ruby-version,.python-version,.prettierrc, and.eslintrcare small and useful after restore. - Review secrets.
.env, private keys, local certificates, and database dumps may be sensitive. They deserve a deliberate policy, not a wildcard accident. - Decide intentionally about Git history.
.git/is hidden and can be large. Excluding it is right for a clean working-tree backup when GitHub, GitLab, or another remote protects history. Including it is right when the backup must preserve local branches, tags, hooks, reflogs, or unpushed commits. - Skip generated hidden caches.
.next/cache/,.turbo/,.pytest_cache/,.mypy_cache/,.ruff_cache/,.gradle/, and similar folders are typically rebuilt by tools.
Rsync patterns for hidden files on Mac
rsync exclude rules are path patterns, not regular expressions. A few examples show why broad hidden-file rules can surprise you:
Safer defaults
--exclude='.DS_Store'skips Finder metadata files wherever they appear.--exclude='.Spotlight-V100/'skips a macOS volume index directory.--exclude='.next/cache/'skips a specific generated cache but can keep.nextstructure if you need it.--exclude='.pytest_cache/'skips Python test cache without removing project config.
Review first
--exclude='.*'skips nearly every dotfile and dotfolder at matching path levels, including useful config.--exclude='.git/'changes the backup from a clone-like copy into a working-tree copy.--exclude='.env'protects secrets, but may omit a local setup file you expected to restore.--exclude='*/.*'can hide nested dotfiles you did not know were part of the build.
For one project, explicit command-line rules are fine. For recurring backups, put the policy in an exclude file so it can be reviewed like code:
# ~/.rsync-mac-dev-excludes
# macOS metadata
.DS_Store
.Spotlight-V100/
.Trashes/
.fseventsd/
# generated developer caches
node_modules/
.next/cache/
.nuxt/
.svelte-kit/
.turbo/
.vite/
.pytest_cache/
.mypy_cache/
.ruff_cache/
__pycache__/
.gradle/
coverage/
dist/
build/
# optional: clean working-tree backup only
# .git/
# optional: secrets policy, review before enabling
# .env
# *.pem
# *.key
Then use the file with a dry run:
rsync -avnih --delete \
--exclude-from="$HOME/.rsync-mac-dev-excludes" \
~/Developer/my-app/ /Volumes/DevBackup/my-app/
Read the itemized output before removing n. You want to see source, tests, docs, manifests, lockfiles, and restore instructions. You should not see dependency trees, build output, cache folders, or macOS metadata. If .editorconfig or .nvmrc vanished from the preview, your pattern is too broad.
Step-by-step fix for clean hidden-file backups
1. List the hidden files before deciding
Start by looking at what you actually have. From the project root, use:
find . -maxdepth 2 -name '.*' -print | sort
Do not run a destructive mirror from that list. Use it to classify paths into four groups: keep, skip, review, and choose per backup type. Keep small config files. Skip machine-generated caches. Review anything secret. Decide whether this backup needs .git/.
2. Keep restore-critical dotfiles
Most project-level dotfiles are tiny. If they help another developer or future-you rebuild the project, keep them. Common examples include .gitignore, .editorconfig, .nvmrc, .node-version, .ruby-version, .python-version, .tool-versions, lint configs, formatter configs, and checked-in templates such as .env.example.
3. Exclude caches and platform junk explicitly
Caches are where sync tools get dragged into unnecessary work. A Next.js app can rebuild .next/cache/. Python can rebuild .pytest_cache/. Gradle can rebuild .gradle/. macOS can recreate .DS_Store. These are good exclude targets because they are reproducible and noisy.
4. Treat secrets separately
Some developers exclude .env from every backup. Others keep encrypted secret archives in a separate password manager or secrets vault. Both are better than letting --exclude='.*' make the decision by accident. If a backup destination is an external SSD in a drawer, your policy may differ from a cloud folder shared across devices.
5. Run a restore test
A clean backup is not just smaller. It should rebuild. Copy the backup to a scratch folder and run the project’s normal setup command: npm ci, pnpm install --frozen-lockfile, pip install -r requirements.txt, bundle install, or the project-specific equivalent. If setup fails because a dotfile is missing, promote that file from skip to keep.
When not to exclude hidden files
Do not exclude hidden files just to make a backup look cleaner. Several cases need them:
- Offline clone backup: keep
.git/if the destination must preserve local history and branches without network access. - Toolchain pinning: keep version files such as
.nvmrc,.ruby-version,.python-version, and.tool-versions. - Editor and formatting policy: keep
.editorconfig, formatter config, lint config, and project-level TypeScript or test config. - Documented sample env files: keep
.env.exampleor.env.templateif they teach the restore process which variables are required.
The good backup is boring, but it is not minimal for its own sake. It preserves the files that explain the project and drops the files that are expensive to copy or unsafe to spread.
When Lsyncer is easier than maintaining hidden-file rules
rsync is still the right answer for many developers. It is transparent, scriptable, and available on macOS. It becomes less pleasant when you need schedules, several folder pairs, visible run history, alerts, mounted-drive checks, and per-project exclusions that someone has to maintain over time.
Lsyncer takes the same filtered-backup idea and turns it into a native macOS workflow. You choose the source and destination, keep generated folders such as node_modules, .git, virtual environments, build output, and caches out of the sync, and run it on demand or on a schedule. It is a one-time $19.99 App Store purchase, not a subscription.
The rule is simple: use rsync when you want to own the command. Use Lsyncer when you want repeatable local project sync with a GUI, status, and fewer fragile shell details. In both cases, the technical policy is the same: back up source-of-truth files, skip generated churn, and review hidden files by purpose.
Best practices for hidden files in Mac project backups
- Avoid blanket dotfile excludes. They are fast to type and easy to regret.
- Keep an exclude file under version control. A small documented policy beats a mystery command in shell history.
- Use dry runs after every pattern change. Hidden-file rules have a wide blast radius.
- Separate source backup from secrets backup. Use the right storage and encryption for credentials instead of treating them as ordinary project files.
- Keep active projects outside cloud-sync roots. Work in
~/Developeror~/Code, then copy a filtered backup where you want it.
Related reading
- rsync exclude-from Mac — move your backup policy into a reusable file instead of a long command.
- rsync exclude multiple directories on Mac — build a safe set of generated-folder rules for developer projects.
- Mac copy folder exclude files — copy project folders cleanly without dragging dependency trees and caches along.
FAQ
How do I make rsync exclude hidden files on Mac?
Use quoted exclude patterns, for example --exclude='.DS_Store' or --exclude='.pytest_cache/'. Avoid starting with --exclude='.*' unless you truly want to skip project dotfiles such as .gitignore, .editorconfig, and version files.
Does --exclude='.*' exclude .gitignore?
Yes. A broad dotfile pattern can exclude useful project files such as .gitignore, .editorconfig, .nvmrc, and other hidden configuration. For developer backups, explicit excludes are usually safer.
Should I exclude .git from rsync backups?
Exclude .git/ for a clean working-tree backup when your remote repository protects history. Keep .git/ if the backup must preserve local branches, tags, hooks, reflogs, or unpushed commits. Decide per backup type.
Should I back up .env files?
Only if you have a deliberate secrets policy. Many teams keep real secrets in a password manager or encrypted vault and back up only .env.example. Do not let a broad hidden-file rule decide this silently.
What hidden files should Mac developers usually exclude?
Common safe exclusions include .DS_Store, .Spotlight-V100/, .Trashes/, .fseventsd/, and generated caches such as .next/cache/, .turbo/, .pytest_cache/, .mypy_cache/, and .gradle/.