# How the FUSE Mount Synchronizes Files Between Durable Objects and the computersd Daemon

> Discover how the FUSE mount synchronizes files between Durable Objects and the computersd daemon. Learn about the 250ms sync loop and capn-web RPC for efficient data transfer.

- Repository: [Cloudflare/computer](https://github.com/cloudflare/computer)
- Tags: internals
- Published: 2026-08-16

---

**The computersd daemon maintains synchronization through a 250ms background sync loop that pulls remote changes from the Durable Object and pushes local modifications back via capn-web RPC.**

The Cloudflare computer project enables containerized workloads to interact with Durable Object storage through a POSIX-like filesystem interface. This article explains the FUSE file synchronization mechanism that keeps local filesystem state consistent with the authoritative Durable Object (DO) storage, based on the implementation in the [cloudflare/computer](https://github.com/cloudflare/computer) repository.

## Overview of the Synchronization Architecture

File synchronization between the Durable Object and the computersd daemon operates through three coordinated layers:

- **Virtual File System (VFS)** — A SQLite-backed filesystem abstraction in the daemon
- **Sync Driver** — The bidirectional replication engine handling change propagation
- **Cap'n Web RPC** — The wire protocol for exchanging changes and watermarks

The VFS resides in [`packages/computerd/src/fuse/vfs.ts`](https://github.com/cloudflare/computer/blob/main/packages/computerd/src/fuse/vfs.ts), while the sync engine lives in [`packages/rpc/src/sync-driver.ts`](https://github.com/cloudflare/computer/blob/main/packages/rpc/src/sync-driver.ts). Both sides share the `SyncRPC` interface defined in the `@cloudflare/computer-rpc` package.

## Creating the VFS with Initial State Pull

When the daemon starts, `createNodeVirtualFileSystem()` in [`packages/computerd/src/fuse/vfs.ts`](https://github.com/cloudflare/computer/blob/main/packages/computerd/src/fuse/vfs.ts) (lines 85–100) constructs the virtual filesystem from a `SQLiteWorkspaceProvider`. If an upstream `SyncRPC` stub is provided, the function immediately performs an **initial pull** to populate the local database with the latest DO state before FUSE mounting occurs.

```typescript
// From packages/computerd/src/fuse/vfs.ts
import { createNodeVirtualFileSystem } from "@cloudflare/computerd";
import { createSyncClient } from "@cloudflare/computer-rpc";

async function mountWithSync(doUrl: string) {
  // Create SyncRPC client pointing at the Durable Object
  const syncRpc = await createSyncClient({ url: doUrl });

  // Build VFS — this performs the initial pull automatically
  const { vfs, stopSync } = await createNodeVirtualFileSystem({ 
    upstream: syncRpc 
  });

  // vfs is now ready for FUSE mounting with current DO state
  // stopSync() terminates the background loop when needed
}

```

The `SQLiteWorkspaceProvider` serves as the local storage engine, maintaining file metadata, directory structures, and blob references in SQLite while the sync mechanism keeps this store converged with the DO.

## The 250ms Background Sync Loop

After initialization, `startSyncLoop()` launches a recurring sync process. The implementation in [`packages/computerd/src/fuse/vfs.ts`](https://github.com/cloudflare/computer/blob/main/packages/computerd/src/fuse/vfs.ts) (lines 123–142) uses `setInterval` to invoke `tick(db, upstream)` every **250 milliseconds** (`SYNC_TICK_MS` constant).

Each tick executes three operations:

1. **`pullOnce`** — Fetches and applies remote changes from the Durable Object
2. **`pushOnce`** — Transmits local modifications to the Durable Object
3. **Watermark updates** — Persists synchronization cursors to ensure progress

Errors during any tick are logged but do not halt the daemon, providing fault-tolerant operation across transient network failures.

```typescript
// Conceptual flow of each sync tick
import { tick } from "@cloudflare/computer-rpc/driver";

async function oneSyncTick(db: Database, upstream: SyncRPC) {
  // Pull: receive ChangeEntry objects from DO, apply to local SQLite
  await pullOnce(db, upstream);
  
  // Push: serialize local changes, transmit via capn-web RPC
  await pushOnce(db, upstream);
}

```

## Sync Driver Implementation Details

The core replication logic resides in [`packages/rpc/src/sync-driver.ts`](https://github.com/cloudflare/computer/blob/main/packages/rpc/src/sync-driver.ts) (lines 69–392). This module implements the `tick`, `pullOnce`, and `pushOnce` functions that coordinate state transfer.

### Pull Operation

`pullOnce` invokes `SyncRPC.fetchChanges` to retrieve **ChangeEntry** objects since the last recorded watermark. The driver guarantees that changes are only persisted after the advertised snapshot cursor is validated, preventing partial application of remote state.

### Push Operation

`pushOnce` collects local modifications, packages them as `ChangeEntry` objects with associated blob data, and transmits via `SyncRPC.pushChanges`. The `pushRev` cursor advances only upon successful DO acknowledgment, ensuring at-least-once delivery semantics without duplicate application.

### Watermark Reconciliation

The `SyncRPC.watermarks` method enables both sides to query and verify their respective cursors. These watermarks stored in the SQLite database (`db`) provide the foundation for eventual consistency—even if individual ticks fail, subsequent sync rounds resume from the last confirmed position.

## Cap'n Web RPC Protocol

The wire format specification in [`docs/08_capnweb_interface.md`](https://github.com/cloudflare/computer/blob/main/docs/08_capnweb_interface.md) defines the contract between DO and daemon. The `@cloudflare/computer-rpc` package exports this interface, used by both parties:

| Method | Purpose |
|--------|---------|
| `fetchChanges(cursor)` | Retrieve changes since the provided watermark |
| `pushChanges(entries, cursor)` | Submit local changes, receive new push revision |
| `watermarks()` | Exchange current cursor positions for verification |

The `ChangeEntry` type and serialization utilities are defined in [`packages/dofs/src/sync/changes.ts`](https://github.com/cloudflare/computer/blob/main/packages/dofs/src/sync/changes.ts), providing the structure for file operations (create, modify, delete) and associated blob references that traverse the network.

## FUSE Integration and POSIX Semantics

The populated VFS is handed to the FUSE driver (`@platformatic/vfs`), which exposes standard POSIX operations:

- `readFileSync` — Satisfied from local SQLite store
- `writeRangeSync` — Buffered locally, synced to DO on next push cycle
- Directory operations — Metadata served from local workspace provider

Because all modifications flow through the SQLite backing store, the 250ms sync loop captures every local change automatically. Applications using the FUSE mount observe standard filesystem behavior while the underlying synchronization remains transparent.

## Summary

- **Initialization**: `createNodeVirtualFileSystem()` pulls current DO state before FUSE mount
- **Active sync**: 250ms loop in `startSyncLoop()` runs `tick()` with `pullOnce`/`pushOnce`
- **Reliability**: Watermarks in SQLite enable resumable, at-least-once synchronization
- **Protocol**: Cap'n web RPC via `SyncRPC` interface exchanges `ChangeEntry` objects
- **Fault tolerance**: Tick errors are logged; sync continues from last confirmed watermark

## Frequently Asked Questions

### How does the sync loop handle network interruptions?

The sync driver in [`packages/rpc/src/sync-driver.ts`](https://github.com/cloudflare/computer/blob/main/packages/rpc/src/sync-driver.ts) treats RPC failures as non-fatal. Errors are logged via the standard logging facility, and the 250ms interval continues executing. Because watermarks are only advanced after successful acknowledgment, the next tick automatically retries from the last confirmed position once connectivity restores.

### What happens if both sides modify the same file simultaneously?

The current implementation follows a **last-writer-wins** policy based on sync timing. The `pullOnce`/`pushOnce` sequence in each tick means local changes push only after remote changes are applied. Conflicts are not automatically merged; the most recent change entry by synchronization order prevails. Applications requiring stronger consistency should implement external locking.

### Can the sync interval be configured?

The `SYNC_TICK_MS` constant in [`packages/computerd/src/fuse/vfs.ts`](https://github.com/cloudflare/computer/blob/main/packages/computerd/src/fuse/vfs.ts) is fixed at 250ms in the current implementation. This balances latency against overhead for typical container workloads. Modifying this value requires source changes and rebuilding the computersd package.

### Is the SQLite database shared between multiple daemon instances?

No. Each computersd daemon maintains its own `SQLiteWorkspaceProvider` instance. The Durable Object serves as the single authoritative source, with each daemon's local database acting as a replica synchronized through the RPC channel. Multiple daemons can mount the same DO, with convergence achieved through the shared watermark protocol.