Delta Sync Application Pattern
Efficient bandwidth via operation deltas with fallback snapshots for state synchronization.
Spec-Version: 1.0.0 | Invariants: docs/invariants.md
Overview
Delta sync sends only state changes (deltas) instead of full state on each update. This reduces bandwidth significantly in collaborative and real-time applications, especially with many concurrent users or large state objects.
Architecture
Server state:
- Maintain global revision counter (incremented per operation)
- Store operation history in ring buffer (e.g., last 1024 operations)
- Keep current state snapshot for far-behind clients
- Track each client's
lastSentRev(last revision sent to that client)
Client state:
- Track
serverRev(last received revision from server) - Maintain pending operations (optimistically applied locally)
- Merge incoming deltas and snapshots into materialized view
Server MUST
- Increment global revision counter on every state change
- Store each operation with its revision in a ring buffer
- For each client, compute delta (operations since
lastSentRev) - If delta is unavailable (client too far behind), send full snapshot instead
- Include revision metadata in state messages:
revfor snapshots,fromRev/toRevfor deltas - Track per-client
lastSentRevto compute deltas correctly
Client MUST
- Track
serverRevfrom received messages - Apply incoming deltas in order (maintain FIFO)
- Fall back to full refresh if
SNAPSHOTreceived instead of deltas - Implement optimistic updates (apply pending ops before server confirmation)
- Rebase pending operations after conflict resolution
Recovery Strategy
When a client falls too far behind (revision gap exceeds buffer size), the server:
- Sends a
REVISION_GAPerror message with metadata about the gap - Then sends a full snapshot for recovery
The client discards pending operations and applies the snapshot, then resumes delta sync on subsequent updates.
text
Client (offline 30s) Server (rev=100, buffer=75-100)
reconnect >
check: expected 50, have 75
(gap too large, send error + snapshot)
< REVISION_GAP $ expectedRev=50, serverRev=100, bufferFirstRev=75
< snapshot $ rev=100, state={}
discard pending $
apply full state $
resume delta sync $Timelines
Happy path (delta sync):
mermaid
sequenceDiagram
participant Client
participant Server as Server (rev=100)
Client->>Server: connect
Note over Server: remember<br/>lastSentRev=0
Server->>Client: snapshot<br/>rev=100, state={}
Client->>Client: lastRev=100
Client->>Client: user action<br/>(pending op)
Server->>Client: delta<br/>rev=101, ops=[op1]
Client->>Client: apply ops<br/>lastRev=101Far-behind recovery (snapshot fallback):
mermaid
sequenceDiagram
participant Client as Client (offline 30s)
participant Server as Server (rev=100,<br/>buffer=75-100)
Client->>Server: reconnect
Note over Server: check: expected 50, have 75<br/>(gap too large,<br/>send snapshot)
Server->>Client: snapshot<br/>rev=100, state={}
Client->>Client: discard pending<br/>apply full stateFailure Modes
| Condition | Error | Retryable | Client Action |
|---|---|---|---|
| Client far behind (rev gap > buffer) | REVISION_GAP | yes | Receive REVISION_GAP metadata, then accept SYNC.SNAPSHOT and discard pending ops |
| Concurrent client updates | (via deltas) | n/a | Apply deltas in order, rebase pending ops, ack confirmed ops via clientReqId |
| Unauthorized update | UNAUTHENTICATED | no | Reconnect with valid credentials and rejoin |
Key Implementation Details
- Ring Buffer — Fixed-size circular buffer prevents unbounded memory growth
- Revision Tracking — Allows efficient delta computation without full state copies
- Per-Client State — Each client has independent
lastSentRevfor personalized deltas - Optimistic Updates — Apply pending ops locally before server confirmation
- Fallback Strategy — Send snapshots when buffer doesn't have enough history
Conformance
Delta sync ships with three fixtures validating core scenarios:
- 001-happy-path — Client joins, receives snapshot, then receives deltas on updates
- 002-revision-gap — Client falls behind buffer, receives
REVISION_GAPerror + snapshot - 003-optimistic-update — Client sends update, receives server confirmation via
clientReqId
Run conformance tests with:
bash
bun test examples/delta-sync/conformance.test.tsLimitations
- No persistence layer; in-memory ring buffer only
- No automatic backpressure; assumes clients handle snapshots gracefully
- No encryption; suitable for trusted networks only