A folder compare and sync Mac workflow is the step that keeps a clean backup from becoming a noisy copy of yesterday's mistakes. Before you mirror a developer project to an external SSD, NAS, iCloud folder, or second Mac, compare what changed, decide what should be excluded, then sync only the files that are worth preserving.
Folder compare and sync Mac workflow for developers
The basic idea is simple: one folder is the source of truth, another folder is the destination, and a compare step shows the difference before a sync step changes anything. The trap is that developer folders are not ordinary document folders. A small app can contain a few hundred source files and tens of thousands of generated files once package managers, virtual environments, build tools, test runners, and Git internals get involved.
If you compare and sync everything blindly, the useful signal gets buried. The files you care about are usually source code, lockfiles, migrations, docs, configuration, scripts, fixtures, and small assets. The files that make sync slow are usually reproducible: node_modules/, .next/cache/, dist/, build/, .venv/, venv/, __pycache__/, vendor/bundle/, target/, .gradle/, coverage output, logs, and temporary files.
For most Mac developers, the safest workflow is:
- Keep active work in a local folder such as
~/Developeror~/Code. - Decide whether the destination is a mirror, archive, or handoff copy.
- Compare source and destination with filters enabled.
- Review deletes separately from copies and updates.
- Run the sync only after the preview looks boring.
- Test a restore occasionally by reinstalling dependencies from lockfiles.
Why folder compare is different for code projects
A compare tool answers the question “what is different?” That sounds objective, but the useful answer depends on your ignore rules. Without filters, a Node.js project can look wildly different every time npm install touches a dependency timestamp. A Python project can fill the compare output with .pyc files. A Rails project can make tmp/, log/, and vendor/bundle/ look more important than the application code.
That is why developer sync needs a distinction between project state and machine state. Project state belongs in the backup: source, lockfiles, schema files, docs, scripts, tests, and configuration that another machine needs to rebuild the app. Machine state is local and disposable: installed packages, compiled artifacts, caches, editor indexes, and OS metadata.
Option 1: compare folders manually with Finder and Terminal
Finder is fine for a quick visual check, but it is not enough for a safe mirror. It will show timestamps and sizes, but it will not explain delete behavior or apply developer-specific exclusions. Use Finder when the folders are small and you are doing a one-off copy. Use Terminal when you need a repeatable answer.
A fast rough comparison is:
diff -qr ~/Developer/my-app /Volumes/Backup/my-app
diff -qr recursively compares two folders and prints only files that differ or exist on one side. It is useful for sanity checks, but it does not have the same copy semantics as a sync tool. If you plan to sync with rsync, preview with rsync too.
For a source-to-destination mirror, use a dry run:
rsync -avnih --delete \
--exclude 'node_modules/' \
--exclude '.git/' \
--exclude '.venv/' \
--exclude 'venv/' \
--exclude 'dist/' \
--exclude 'build/' \
--exclude '.next/cache/' \
~/Developer/my-app/ /Volumes/Backup/my-app/
The -n flag means dry run. The -i flag prints itemized changes. Keep both while you review. Look for unexpected deleting lines, nested destination paths such as my-app/my-app/, and generated folders that should have been excluded.
Option 2: use FileMerge or visual compare tools for review
macOS developers who install Xcode also get FileMerge as part of the developer tools. It is better for inspecting a few changed files than for running a large folder sync. You can launch it from Xcode's additional tools or from Terminal if available:
opendiff ~/Developer/my-app/src /Volumes/Backup/my-app/src
Visual comparison is useful when you need to inspect source changes before overwriting a destination. It is less useful for dependency trees because there is nothing meaningful to review inside most generated packages. If a visual compare tool spends most of its time indexing node_modules, the problem is not the UI; the problem is the sync set.
Good visual compare candidates:
- Configuration folders where small text changes matter.
- Docs and markdown files that were edited outside Git.
- Small scripts or migrations copied between machines.
- Project templates where you intentionally compare two variants.
Poor visual compare candidates:
node_modules/,.pnpm-store/,.yarn/cache/, and package manager internals..git/object databases. Use Git commands to compare Git history.- Build outputs such as
dist/,build/,.next/, andcoverage/. - Virtual environments and compiled Python bytecode.
Option 3: compare and sync with rsync
rsync is still the baseline for reliable folder sync on Mac because it is explicit and scriptable. The downside is that you own every path, every exclude rule, every schedule, and every log. That tradeoff is fine if you are comfortable in Terminal. It is risky if your backup script is something you wrote once and never read again.
For recurring developer backups, create an exclude file instead of pasting rules into every command:
cat > ~/.rsync-dev-excludes <<'EOF'
node_modules/
.pnpm-store/
.yarn/cache/
.next/cache/
.nuxt/
dist/
build/
coverage/
.turbo/
.vite/
.git/
.venv/
venv/
__pycache__/
.pytest_cache/
.mypy_cache/
vendor/bundle/
target/
.gradle/
.DS_Store
EOF
Then preview the sync:
rsync -avnih --delete \
--exclude-from "$HOME/.rsync-dev-excludes" \
~/Developer/my-app/ /Volumes/Backup/my-app/
If the preview is correct, run the same command without -n:
rsync -avih --delete \
--exclude-from "$HOME/.rsync-dev-excludes" \
~/Developer/my-app/ /Volumes/Backup/my-app/
Do not rewrite the command from memory between preview and real run. Edit as little as possible. The safest habit is to remove only the n from -avnih.
Option 4: use an app-based folder sync workflow
A folder sync app makes sense when you want the same discipline as a filtered rsync workflow without maintaining scripts. For developer projects, the app must support exclusions. A generic “copy changed files” tool that indexes node_modules is just Finder with extra steps.
This is where LSyncer fits. It is a native macOS app for recurring folder sync with developer-focused exclusions for folders such as node_modules, .git, virtual environments, build output, and caches. It is not trying to replace Git or inspect source diffs line by line. It is for the backup and handoff layer: keep a clean project mirror on another folder, drive, or cloud destination without dragging generated junk into the sync.
Use an app-based workflow when you want:
- Schedules that run without keeping a terminal window or shell script open.
- Visible sync status, last-run timestamps, and failure signals.
- Per-folder rules for different projects and destinations.
- A one-time Mac app purchase instead of another subscription for a small local workflow.
For LSyncer specifically, the positioning is intentionally narrow: $19.99 one-time, local by default, built for Mac developer folders that generic cloud sync tools handle poorly. If you already love your rsync scripts, keep them. If you keep putting off clean backups because the scripts are annoying, a small app can be the more reliable system.
Best practices before syncing project folders
- Keep Git as the history layer. Folder sync is not a replacement for commits, branches, pull requests, or remote repositories.
- Use folder sync as the recovery layer. Sync the working copy, docs, local scripts, and config that make a project easy to restore.
- Exclude generated folders by default. Rebuild dependencies from lockfiles instead of preserving huge machine-local trees.
- Review deletes separately. Deletes are normal in mirrors, but they should never be surprising.
- Avoid active projects inside cloud-synced folders. If you want iCloud, Dropbox, OneDrive, or Google Drive involved, sync a clean mirror into the cloud destination instead of running the live project there.
- Test restore, not just backup. Copy the destination to a scratch folder and run
npm ci,pnpm install,bundle install, orpip install -r requirements.txt.
Related reading
- Mac sync two folders — practical Finder,
ditto,rsync, and filtered app workflows. - Rsync dry run on Mac — preview copy and delete behavior before changing a backup destination.
- File sync for Mac developers — choosing a sync workflow that skips generated junk and keeps status visible.
FAQ
What is the best way to compare and sync folders on Mac?
For a one-time check, use Finder, diff -qr, or FileMerge. For repeatable folder sync, use rsync -n to preview changes before a real sync, or use a Mac sync app with visible status and exclusions. Developer folders should be filtered before comparison so generated files do not dominate the result.
Can I compare two folders on Mac before using rsync?
Yes. You can use diff -qr source destination for a rough recursive comparison, but the best preview is usually rsync -n -i with the exact excludes and destination you plan to use. That shows the changes rsync would actually make.
Should I include node_modules when syncing project folders?
Usually no. node_modules is large, noisy, and reproducible from a lockfile. Sync package.json, package-lock.json, pnpm-lock.yaml, or yarn.lock, then reinstall dependencies on the destination if you need to run the project there.
Is iCloud Drive safe for syncing code folders?
iCloud Drive is fine for a filtered copy of a code folder, but it is a poor place for active dependency-heavy work. Package managers create thousands of small files quickly, which can make iCloud appear stuck or push bird CPU high. Keep active projects local and sync a clean mirror when needed.
What should a Mac developer folder sync exclude?
Start with node_modules/, .git/, .venv/, venv/, vendor/bundle/, dist/, build/, coverage/, .next/cache/, __pycache__/, .pytest_cache/, target/, .gradle/, logs, temporary files, and macOS metadata such as .DS_Store. Add stack-specific caches as you find them.