If you’ve ever had phantom files reappear after deleting them, mysterious sync conflicts, or watched your iCloud folder slowly descend into chaos while running build scripts, I share your pain. If not, it's just around the corner if you try using iCloud for development work. My sleuthing did not turn up a good reference explaining the underlying issue, so I thought I'd share what I found.
The core issue is that iCloud Drive looks like a regular folder, but it isn’t. It’s a synchronized database with multiple layers of state tracking, and most command line developer tools completely ignore them. Here’s a breakdown of what's happening.
How iCloud File Tracking Works
Let's start with a little background. iCloud uses a multi-layered approach to track file changes, which includes:
-
File System Events (FSEvents): macOS has a system called FSEvents that notifies apps when files change. iCloud’s
birddaemon subscribes to these events for iCloud folders. When you use Finder, it properly triggers FSEvents that iCloud can see. -
iCloud Database (client.db): iCloud maintains a SQLite database tracking every file’s state. It contains metadata like sync status, file hashes, server identifiers, and modification dates, mapping local file paths to iCloud document IDs.
-
File Coordination APIs: Apps are supposed to use
NSFileCoordinatorand related APIs. These ensure atomic operations and proper notifications. Finder and well-behaved apps use these; command line tools typically don’t. -
CloudDocs File Provider: Modern iCloud uses a “File Provider” system that acts as an intermediary between apps and actual file storage. It handles on-demand downloading, upload queuing, and conflict resolution.
Why Command Line Tools Breaks Things
This system works great when working with files through the Finder and with apps that follow best-practices, but unfortunately, many development tools (Unix) do not know how to play by the rules of iCloud. Here's an example of how things can go wrong:
Bypass of Coordination
# This bypasses all iCloud APIs:
rm ~/Desktop/myfile.txt
# iCloud never gets notified the file is gone
# Database still thinks: "myfile.txt needs to be synced"
-
Missing FSEvents Context: While command line tools do generate FSEvents, they do so without the proper context that GUI apps provide. iCloud might see “file deleted” but not know it was intentional vs. a sync conflict.
-
Database Inconsistency: When you
rma file, the file disappears from disk, but the iCloud database still has an entry. Thenbirdtries to sync a non-existent file, creating the “phantom file” problem.
Race Conditions
# This can create race conditions:
mv large_file.zip ~/Desktop/ # Finder starts uploading
rm ~/Desktop/large_file.zip # You delete before upload completes
# iCloud is now confused about file state!
This is actually quite a common pattern, because large files take a while to upload, leaving plenty of time to invalidate that state!
What's the “Proper” Way?
If you must work in iCloud folders, use trash instead of rm:
# Better - goes through proper deletion APIs:
trash ~/Desktop/myfile.txt
# Or use the Finder API:
osascript -e 'tell app "Finder" to delete POSIX file "/path/to/file"'
If you’re writing apps, use file coordination:
NSFileCoordinator *coordinator = [[NSFileCoordinator alloc] init];
[coordinator coordinateWritingItemAtURL:url
options:NSFileCoordinatorWritingForDeleting
error:&error
byAccessor:^(NSURL *writingURL) {
// Perform deletion here
}];
This isn't always possible though, as you may be running a build or deployment script with who knows how many calls to fix!
Why This Matters
Local files are simpler: delete a file, and it’s gone (because it's just a typical file system). But iCloud "files" exist in multiple places: local cache, iCloud database entries, Apple’s servers, and other devices.
Command line operations only affect the local cache, leaving the other layers inconsistent. Sometimes iCloud can detect and resolve issues, but that can break down, especially when rm-ing files while syncing other large files. That’s why you sometimes have to nuke the entire local iCloud state to force a clean rebuild (or even update the local SQLite if you so dare).
The takeaway: iCloud folders aren’t just folders—they’re synchronized databases that need proper API usage to stay consistent. It's best to keep your code projects in a local directory, and let iCloud handle documents that you work on through the Finder and apps, not the terminal.