Skip to content
macOSDeep Dive Published Updated 6 min readViews unavailable

File Provider on macOS: Domains, Placeholders, and System-Managed Sync

How replicated File Provider extensions expose remote storage through Finder while macOS manages local copies, placeholders, enumeration, and change flow.

A cloud-storage client on macOS cannot treat Finder integration as a folder plus a background download loop. Apple’s File Provider framework gives the system a structured view of remote items and assigns macOS responsibility for local materialization, eviction, coordination, and presentation. The provider extension translates between that system model and the service’s remote API.

For a modern macOS provider, the central type is NSFileProviderReplicatedExtension. The system maintains the local replica. The extension enumerates remote state, fetches content when requested, uploads local changes, and reports remote changes back to the system.

A domain is a synchronization boundary

An NSFileProviderDomain represents one provider-managed location. A provider can use separate domains for different accounts, teams, or storage roots. The host app adds and removes domains through NSFileProviderManager; the system then creates the visible location and runs the corresponding extension as needed.

Domain identifiers and item identifiers must be stable. A path is a poor item identity because users rename and move files. The provider should retain a remote object’s durable ID and report its current parent and filename as metadata. If a server recycles identifiers or exposes only paths, the client needs its own mapping layer.

Deleting a domain is not the same as logging out remotely. Decide what happens to unsynchronized local changes, revoke tokens in the extension’s shared storage, and remove the domain only after the user understands which local state may disappear.

Placeholders separate namespace from bytes

Finder can display an item before its content is resident. The provider supplies metadata through an object conforming to NSFileProviderItemProtocol: identifier, parent, filename, type, capabilities, version information, dates, and other properties. The system uses that metadata to represent a placeholder.

When an application needs the bytes, macOS asks the extension to fetch or create the content. This allows a large remote tree to remain browsable without downloading every object. It also means the extension must not interpret “visible in Finder” as “available offline.”

Materialization and eviction are system decisions influenced by user actions, storage pressure, pinning, and policy. Cache state is not authoritative remote state. A provider must be able to re-fetch content and should never rely on a temporary materialized URL as a permanent identifier.

Enumerators provide snapshots and changes

The system requests an NSFileProviderEnumerator for a container such as the root, a directory, or the working set. An initial enumeration supplies pages of items. Subsequent change enumeration uses a sync anchor so the provider can return changes since a known point.

The anchor represents remote history, not merely a wall-clock timestamp. Timestamps collide, clocks move, and an API page can change while it is being read. Prefer a server cursor or monotonically ordered change token. If the server can no longer honor an old cursor, expire the anchor and force a controlled rescan instead of silently skipping the missing interval.

When remote state changes outside the Mac, call the manager’s signaling API for the affected container. Signaling does not itself deliver the changes; it tells the system to ask the enumerator. Coalesce notifications, but do not collapse distinct server cursors into an ambiguous “something changed” flag that cannot support recovery.

Local operations are asynchronous contracts

The replicated extension receives requests to create, modify, delete, and fetch items. Each request includes versions and fields that let the provider distinguish content changes from metadata changes. A correct implementation preserves operation identity through retries so a timeout does not create the same remote object twice.

Conflict handling belongs in the product design. If the remote version changed after the local edit began, overwriting it may lose data. The extension can return a structured File Provider error and let the system surface the conflict, or implement a documented server-side merge. Generic success after a partial upload is worse than a visible retry.

Cancellation also matters. The system may stop a fetch when the requesting application closes. Cancel remote work when safe, clean temporary files, and make completion handlers run exactly once. Extensions are relaunched; in-memory queues alone cannot represent durable pending uploads.

Credentials and diagnostics live outside Finder

The host app normally handles account UI and stores credentials in an access group available to the extension. Use short-lived access tokens and a refresh design that can recover when either process is terminated. Do not place secrets in item metadata, filenames, logs, or provider error strings.

Instrument enumeration duration, page counts, anchor expiration, materialization bytes, operation retries, conflicts, and server status classes. File Provider metrics and logs should make it possible to answer whether an item is absent remotely, filtered by enumeration, awaiting materialization, or blocked by a failed local operation.

Reconcile from durable truth after interruption

The extension can be terminated between any two callbacks, so a local operation needs durable phases rather than one in-memory Boolean. Persist the remote request identifier, expected item version, uploaded-content identity, and completion state before reporting success. On relaunch, query the server by that identifier and continue or reconcile; blindly replaying a create can duplicate data, while blindly declaring success can lose a local edit.

Enumeration needs the same discipline. A page token belongs to one snapshot or change sequence and should not be reused after its server-side context expires. Return the framework’s appropriate expiration result, establish a new snapshot, and compare stable item identifiers. Do not synthesize a later anchor from the client’s clock or from the last filename seen on one page.

Test rename, move, and delete conflicts across two Macs plus the service’s web interface. Include case-only renames, moves into a deleted parent, concurrent edits, revoked sharing access, token expiration during upload, and a provider process killed after the server commits but before the completion handler runs. Each scenario should converge to one remote item and one understandable local result.

The acceptance test should also include eviction and offline use. Pin a file, disconnect the network, open it through Finder and a non-Apple application, reconnect, edit remotely, and observe the version transition. A provider is reliable when it can reconstruct state after termination and network loss, not merely when a freshly installed demo account completes one uninterrupted synchronization.

File Provider works because macOS owns the local filesystem experience while the extension owns the translation to remote truth. Treating that split as a protocol, with stable IDs and replayable state, is what keeps Finder from becoming a fragile view of a background sync script.

Related:

Sources:

Comments