A Syncthing folder out of sync on Mac usually means the tool is doing exactly what you asked, but the folder shape is wrong for continuous peer-to-peer sync. Developer projects make that especially visible: one npm install, one Python virtual environment, or one framework cache can create thousands of tiny files that keep the folder from reaching a calm, consistent state.
Syncthing folder out of sync on Mac: first checks
Start with the boring checks before changing ignore rules or deleting files. In the Syncthing web UI, open the affected folder and look at the exact reason for the state. “Out of Sync” can mean a real transfer is still pending, a device is offline, a path is ignored on one side but not the other, a permission error stopped a file from being written, or a conflict file was created because two devices changed the same path.
For a Mac developer folder, the first useful question is not “How do I force it green?” It is: what kind of files are preventing convergence? If the pending list is source files such as src/api.ts, README.md, or schema.sql, fix the sync problem. If the pending list is mostly node_modules/, .next/cache/, .venv/, __pycache__/, dist/, logs, or build output, fix the folder design.
On macOS, also check whether the project is inside another sync engine. Paths under ~/Library/Mobile Documents/com~apple~CloudDocs, ~/Dropbox, ~/Library/CloudStorage/GoogleDrive-..., ~/Library/CloudStorage/OneDrive-..., or a provider-managed folder can stack multiple watchers on the same tree. Syncthing may finish a local scan, then iCloud or another client rewrites placeholders, metadata, or availability state underneath it. That makes a small code project feel like it never settles.
Why Syncthing folders stay out of sync for developers
Syncthing works by scanning folders, indexing file metadata, exchanging block information with other devices, and reconciling differences. That model is strong for normal user data: documents, notes, images, PDFs, dotfiles, and project source. It becomes noisy when the folder contains machine-generated state that changes faster than humans can reason about it.
A JavaScript project is the classic example. node_modules can contain tens of thousands of files. Some packages include platform-specific binaries. Frameworks add .next, .nuxt, .svelte-kit, .turbo, .vite, or coverage. Python projects add .venv, __pycache__, .pytest_cache, .mypy_cache, and wheel caches. Ruby, Rust, Go, Java, and mobile projects have their own versions of the same problem.
Those files are not valuable because they are copied. They are valuable because they can be recreated from durable inputs: source code, manifests, lockfiles, build scripts, and configuration. When a sync tool treats the generated tree as first-class data, every install, test run, hot reload, and package-manager cleanup becomes sync work. The folder can look permanently out of sync even though the important project state is already available on both Macs.
Fix 1: confirm connectivity and failed items
Before editing a project, confirm that this is not a simple connectivity or filesystem failure. In Syncthing, check that the remote device is connected, the folder is shared with the expected device, and both sides agree on the folder ID. If one device is paused, disconnected, or using a different folder path than you think, ignore rules will not solve the state.
Then inspect the failed items list. On macOS, failures often come from permissions, locked files, package-manager files changing during a scan, or files that disappeared before Syncthing could read them. If a file is being rewritten by a dev server, stop the server and rescan. If the failed path is inside node_modules, .venv, or a cache directory, that is a strong sign the path should not be in the sync set.
Also make sure both Macs can write to the folder. External drives, network volumes, and restored folders can have ownership or permission differences. A quick Finder copy test into the destination folder can reveal whether the problem is Syncthing-specific or a broader write-access issue. If permissions are wrong, fix the folder ownership and try a rescan before changing the sync topology.
Fix 2: add a real .stignore before the next scan
If generated files are causing the churn, put a .stignore file at the root of the Syncthing shared folder. The root matters. If Syncthing shares ~/Developer, put it at ~/Developer/.stignore. If Syncthing shares ~/Developer/my-app, put it at ~/Developer/my-app/.stignore.
// JavaScript and frontend
**/node_modules
**/.pnpm-store
**/.yarn/cache
**/.next
**/.nuxt
**/.svelte-kit
**/.turbo
**/.vite
**/dist
**/build
**/coverage
// Python
**/.venv
**/venv
**/__pycache__
**/.pytest_cache
**/.mypy_cache
**/.ruff_cache
// Ruby, Rust, Java, macOS
**/vendor/bundle
**/target
**/.gradle
**/.DS_Store
The **/ prefix is useful for monorepos because generated folders may live under apps/web/node_modules, packages/ui/dist, or services/api/.venv. Keep the list explicit. Do not blindly ignore every folder named cache or build unless you know your repositories never store source assets there.
After saving .stignore, rescan the folder on each device. If ignored files already exist on both Macs, the ignore file may prevent future sync activity without cleaning every existing copy. Delete generated folders only when you are sure they are rebuildable, and run the relevant package-manager command afterward:
cd ~/Developer/my-app
rm -rf node_modules .next/cache
npm ci
For pnpm, Yarn, Python, or Ruby projects, use the equivalent lockfile-respecting install command. The goal is to keep reproducible machine state local to each Mac.
Fix 3: move active code out of cloud-managed folders
A common Mac setup is to keep ~/Desktop and ~/Documents in iCloud Drive, then create projects there because the folders are convenient. That is fine for documents. It is usually a poor place for active code. If Syncthing and iCloud Drive both watch the same project, every generated file event can be scanned by both systems.
Move active projects to a local workspace:
mkdir -p ~/Developer
mv ~/Library/Mobile\ Documents/com~apple~CloudDocs/Projects/my-app ~/Developer/my-app
Then decide what should be shared. You can point Syncthing at the local folder with strict ignores, or keep Syncthing pointed at a separate clean copy. The second pattern is often calmer for large projects: your editor and package manager work in ~/Developer/my-app, while the sync destination receives a filtered copy that excludes generated folders from the beginning.
Fix 4: use a filtered copy instead of the live worktree
For small projects, sharing the live worktree can be acceptable. For large Node, Python, Ruby, Rust, or mobile projects, a filtered copy is easier to reason about. The active folder stays local. A separate sync folder receives source files, lockfiles, configs, docs, migrations, and assets. Syncthing then syncs that cleaner folder between devices.
A command-line version looks like this:
rsync -av --delete \
--exclude 'node_modules/' \
--exclude '.git/' \
--exclude '.next/' \
--exclude '.venv/' \
--exclude 'venv/' \
--exclude '__pycache__/' \
--exclude 'dist/' \
--exclude 'build/' \
--exclude 'coverage/' \
~/Developer/my-app/ ~/Syncthing/CodeBackups/my-app/
Preview destructive syncs before running them for real:
rsync -avn --delete \
--exclude 'node_modules/' \
--exclude '.git/' \
--exclude '.next/' \
~/Developer/my-app/ ~/Syncthing/CodeBackups/my-app/
This pattern changes the problem from “make Syncthing understand my entire dev environment” to “give Syncthing a stable project copy.” It also makes restore testing cleaner: clone or copy the synced folder, install dependencies locally, run tests, and confirm the project works without a stale dependency tree.
Fix 5: use LSyncer for recurring filtered Mac sync
If the filtered-copy approach makes sense but you do not want to maintain another shell script, LSyncer is built for that local Mac layer. You choose a source folder and destination, use developer-friendly exclusions for node_modules, .git, virtual environments, build output, and caches, and keep sync status visible instead of hoping a background command ran correctly.
LSyncer is not a replacement for Git, Syncthing, Time Machine, or every backup tool. It is the piece that creates a clean project copy before those systems touch it. That can be a local destination, an external SSD, a NAS-mounted folder, a cloud-provider folder, or a Syncthing folder that should receive only the useful project state. The app is a one-time $19.99 Mac App Store purchase, with no subscription.
Best practices to keep Syncthing in sync on Mac
- Use Git for source history. Syncthing can move files, but Git is better for commits, branches, review, and conflict resolution.
- Do not sync dependency installs. Keep
package.json, lockfiles,pyproject.toml,Gemfile.lock, and similar source-of-truth files; rebuild dependencies per Mac. - Add ignores before the first large scan. Preventing
node_modulesfrom entering the shared state is easier than cleaning it up later. - Avoid stacked sync engines. Do not put an active Syncthing developer folder inside iCloud Drive, Dropbox, Google Drive, OneDrive, or Box unless you are intentionally syncing a filtered copy.
- Watch failed items, not just color. A green folder with the wrong files is less useful than a short failed list that points to the exact problem.
- Test restores. On the second Mac, install dependencies from lockfiles and run the app or test suite. A sync workflow is only trustworthy if restore works.
Related reading
- Syncthing exclude
node_moduleson Mac — exact.stignorepatterns for keeping dependency trees out of peer-to-peer sync. - Sync files between two Macs — broader two-Mac developer workflows using Git, rsync, cloud bridges, and filtered copies.
- Free folder sync software Mac — compare rsync, FreeFileSync, Syncthing, Unison, and app-based filtered sync for developer folders.
FAQ
Why is my Syncthing folder out of sync on Mac?
Common causes include an offline device, mismatched folder sharing, failed file writes, permission issues, conflict files, ignore-rule differences, or generated developer folders such as node_modules and caches changing during scans.
Should I force rescan when Syncthing is out of sync?
Rescan after checking the failed items and fixing the underlying cause. If the pending files are generated folders, add or correct ignore rules first; otherwise the rescan may just repeat the same noisy workload.
Can Syncthing sync node_modules between Macs?
It can, but it is usually the wrong workflow. Sync package.json and the lockfile, then run npm ci, pnpm install --frozen-lockfile, or the project’s package-manager command on each Mac.
Where does .stignore go on macOS?
Put .stignore at the root of the folder Syncthing shares. If the shared folder is ~/Developer, use ~/Developer/.stignore. If it is one project, use that project’s root.
Is LSyncer a replacement for Syncthing?
No. LSyncer is a native Mac folder sync app for creating clean local or destination copies with developer exclusions. It can complement Syncthing by preparing a filtered project folder that avoids dependency and cache churn.