iCloud Drive waiting to upload on Mac is easy to misread as a network problem. Sometimes it is. For developers, though, the message often appears right after a normal project operation: npm install, pnpm install, git checkout, python -m venv .venv, bundle install, or a build that rewrites dist. Finder says files are waiting. The cloud icon stays half-finished. Your Mac may feel hot, loud, or sluggish even if Safari and Slack are the only visible apps.
The key detail is that iCloud Drive is not deciding whether your project is important. It is trying to process every file event in the folder. A source file is one useful object. A dependency directory can be tens of thousands of tiny objects, most of which should never be backed up individually. This guide shows how to find the folder keeping iCloud in the waiting state, clear the queue safely, and rebuild your workflow so code is backed up without pushing disposable developer junk through iCloud.
Why iCloud Drive waiting to upload happens with code projects
When iCloud Drive says files are waiting to upload, macOS has local changes that have not reached iCloud yet. For a document folder, that usually means a few files are queued behind a slow connection. For a development folder, it can mean the sync engine is buried under filesystem churn.
Development tools are noisy by design:
node_modulesmay contain 30,000 to 100,000 files, plus symlinks and package metadata..gitrewrites object files, refs, indexes, locks, and metadata during branch changes, rebases, fetches, and commits..venv,venv,vendor/bundle, and similar dependency folders recreate libraries that already have a lockfile or manifest..next,dist,build,coverage,.turbo,.cache, and test output are meant to be thrown away and rebuilt.
File count matters more than raw size. A 2 GB video is a large upload, but it is still one file. A small JavaScript project can create a 200 MB dependency tree split across tens of thousands of files. iCloud has to notice, inspect, queue, upload, retry, and reconcile those changes. If a dev server or package manager keeps writing while that is happening, the queue never gets a clean idle moment.
Confirm the iCloud upload queue is caused by a developer folder
Start in Finder. Open iCloud Drive, switch to list view, and look for folders whose status icon is stuck. If the waiting status clusters around one repository or project workspace, treat that folder as the suspect.
You can inspect the iCloud Drive directory from Terminal. The default path is:
~/Library/Mobile Documents/com~apple~CloudDocs
Search for dependency and generated folders inside iCloud Drive:
cd ~/Library/Mobile\ Documents/com~apple~CloudDocs
find . -name node_modules -type d -prune -print
find . -name .git -type d -prune -print
find . \( -name .venv -o -name venv -o -name vendor -o -name .next -o -name dist -o -name build -o -name coverage -o -name .turbo -o -name .cache \) -type d -prune -print
Then check whether any folder has a file count that looks like a sync-engine stress test:
find node_modules -type f 2>/dev/null | wc -l
find .git -type f 2>/dev/null | wc -l
find .venv venv vendor/bundle -type f 2>/dev/null | wc -l
find .next dist build coverage .turbo .cache -type f 2>/dev/null | wc -l
Do not obsess over exact numbers. You are trying to separate human-authored project files from generated trees. If a waiting upload queue points at thousands of disposable files, the fix is usually to stop syncing those files, not to wait longer.
Fix 1: stop active writers before touching iCloud
First, stop the programs that are still changing the folder. Quit dev servers, test watchers, Storybook, Docker Compose stacks, package installs, and IDE indexing on that project. Close the workspace in VS Code or JetBrains if the editor is scanning a large tree.
Check for obvious background processes:
ps aux | egrep 'node|pnpm|npm|yarn|python|ruby|bundle|vite|webpack|turbo|xcodebuild' | grep -v grep
Also look at iCloud-related processes in Activity Monitor or Terminal:
ps aux | egrep 'bird|cloudd|fileproviderd|mds|mdworker' | grep -v grep
If CPU activity drops after stopping the project tools, give iCloud a quiet window. The queue may move on its own once new writes stop arriving. Restarting the Mac can help only after you stop the churn; otherwise the same generated folder wakes up and refills the queue.
Fix 2: remove generated files from the iCloud copy
If the stuck folder is a project, remove files that can be recreated from source and lockfiles. Before running destructive commands, confirm your source files, lockfiles, and uncommitted changes are safe. Use git status if the project is a Git repository.
For Node.js projects:
rm -rf node_modules .next dist build coverage .turbo .cache
npm install
For Python projects:
rm -rf .venv venv __pycache__ .pytest_cache .mypy_cache .ruff_cache
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
For Ruby projects:
rm -rf vendor/bundle .bundle tmp/cache log/*.log
bundle install
The second command in each example recreates dependencies. Do that in a local working copy, not inside iCloud Drive, if you want the waiting-to-upload problem to stay fixed. Rebuilding node_modules in the synced folder simply creates the same upload queue again.
Fix 3: move active repositories out of iCloud Drive
For daily development, keep active repositories somewhere local: ~/Developer, ~/Code, or a project folder outside ~/Library/Mobile Documents/com~apple~CloudDocs. Git already handles source history. Package managers already rebuild dependencies. iCloud should not be your live development filesystem.
mkdir -p ~/Developer
mv ~/Library/Mobile\ Documents/com~apple~CloudDocs/my-app ~/Developer/my-app
After moving the project, open it from the local path and reinstall dependencies there. If you still want cloud access to a copy, sync a filtered backup into iCloud Drive instead of putting the live repository there.
Fix 4: use a filtered sync for backups
A filtered sync copies the files you would actually need to restore the project: source, docs, small config files, manifests, and lockfiles. It skips dependency trees, caches, build output, logs, and usually .git internals if the repository already has a remote.
With rsync, the pattern looks like this:
rsync -av --delete \
--exclude 'node_modules/' \
--exclude '.git/' \
--exclude '.venv/' \
--exclude 'venv/' \
--exclude 'vendor/bundle/' \
--exclude '.next/' \
--exclude 'dist/' \
--exclude 'build/' \
--exclude 'coverage/' \
--exclude '.turbo/' \
--exclude '.cache/' \
~/Developer/my-app/ \
~/Library/Mobile\ Documents/com~apple~CloudDocs/Backups/my-app/
Run a dry run before enabling --delete:
rsync -avn --delete \
--exclude 'node_modules/' \
~/Developer/my-app/ \
~/Library/Mobile\ Documents/com~apple~CloudDocs/Backups/my-app/
Read the output carefully. rsync is reliable, but it will do exactly what you ask, including deleting files from the destination if the source and destination are wrong.
Good candidates for iCloud backup
- Source files, templates, and project docs
package.json,package-lock.json,pnpm-lock.yaml,pyproject.toml,Gemfile- Small config files you maintain manually
- Notes, diagrams, and scripts that are part of the project
Files to leave out
node_modules,.venv,venv,vendor/bundle.gitinternals when GitHub, GitLab, or another remote stores historydist,build,.next,coverage,.turbo- Logs, local databases, screenshots from tests, and tool caches
Where .nosync helps and where it does not
Folders ending in .nosync are commonly treated by macOS as local-only inside iCloud Drive. That can be useful for scratch folders you control:
mkdir tmp.nosync
mkdir local-db.nosync
mkdir playwright-output.nosync
Use this for temporary output, not as a general fix for dependency directories. Renaming node_modules to node_modules.nosync breaks normal Node resolution. Symlinking around that can work until one installer, watcher, or teammate script assumes the standard path. For ecosystem folders, the cleaner answer is to keep the active project outside iCloud and sync a filtered copy.
A practical workflow for Mac developers
A stable setup is boring in the best way:
- Keep active repositories in
~/Developeror~/Code. - Use Git remotes for source history and collaboration.
- Back up source and project metadata to iCloud Drive, an external disk, NAS, or another local folder.
- Exclude dependency folders, build output, caches, local databases, and logs.
- Schedule the backup when the project is relatively quiet, not while a dev server is rebuilding every few seconds.
Lsyncer exists for this exact pattern. It is a native macOS folder sync app built for developer folders, with exclusions for node_modules, .git, virtual environments, build folders, and caches. You choose the source and destination, review what is excluded, and run the sync manually or on a schedule. It is a $19.99 one-time purchase, not a subscription.
The point is not to make iCloud better at syncing node_modules. The point is to stop asking it to. Keep the live project fast, keep the backup clean, and let generated files remain generated.
Related reading
- iCloud Drive sync pending on Mac — diagnose a pending queue after dependency installs or branch changes.
- How to stop iCloud from syncing certain folders on Mac — practical options for local-only folders and filtered sync.
- File sync for Mac developers — compare Finder,
ditto,rsync, cloud sync, and filtered app workflows.
FAQ: iCloud Drive waiting to upload on Mac
Why does iCloud Drive say waiting to upload for hours?
For developers, the common cause is a folder that keeps changing while iCloud is trying to upload it. node_modules, .git, virtual environments, build folders, and caches can create thousands of small changes. Stop active writers first, then remove generated folders from the synced copy.
Should I store code projects in iCloud Drive?
It is safer to keep active repositories outside iCloud Drive and back up a filtered copy. iCloud works well for documents. Live code projects generate dependency trees, lock files, caches, and build output that make cloud sync noisy and slow.
Can I exclude node_modules from iCloud Drive?
iCloud Drive does not offer a normal per-folder exclusion UI like developer backup tools do. .nosync can help for scratch folders, but it is not a clean solution for node_modules. A filtered sync tool or an rsync script is usually more predictable.
Is it safe to delete node_modules to clear the upload queue?
Usually yes, if the project has a valid package.json and lockfile. You can recreate it with npm install, pnpm install, or yarn install. Do not delete source files, lockfiles, or uncommitted work. Run git status first if the project is tracked by Git.
What is the fastest long-term fix?
Move active projects to a local folder such as ~/Developer, keep source history in Git, and sync a filtered backup that excludes dependencies and caches. That removes the workload that makes iCloud Drive wait to upload in the first place.