Skip to main content
Technology & EngineeringLocal First285 lines

local-first-fundamentals

Teaches the local-first software paradigm where applications store data on the user's device, work fully offline, and sync to peers or servers when connectivity is available. Covers the spectrum from cloud-first to offline-first to local-first, core benefits (instant UX, offline capability, data ownership, privacy), key challenges (conflict resolution, sync complexity, storage limits), architectural patterns, and decision frameworks for when local-first is the right choice.

Quick Summary26 lines
Build software that works offline, keeps data on the user's device, and syncs when connected.

## Key Points

- Data lives on the server
- App is a thin client rendering server state
- Offline = broken
- Examples: traditional SaaS, Google Docs (pre-offline), most web apps
- Data cached locally for offline use
- Server remains the authority
- Conflicts resolved server-side (last-write-wins or manual)
- Examples: Progressive Web Apps with service workers, mobile apps with local caches
- Data originates and lives on the device
- Every device holds a full (or partial) replica
- Sync is peer-to-peer or via relay servers
- Conflicts resolved automatically via CRDTs or similar

## Quick Example

```
Cloud-First:    Device  -->  Server (authority)  -->  Device
Offline-First:  Device  -->  Cache locally  -->  Server when available
Local-First:    Device (authority)  <-->  Sync  <-->  Device (authority)
```
skilldb get local-first-skills/local-first-fundamentalsFull skill: 285 lines
Paste into your CLAUDE.md or agent config

Local-First Fundamentals

Build software that works offline, keeps data on the user's device, and syncs when connected.


What Local-First Means

Local-first software stores the primary copy of data on the user's device. The server is a peer, not the authority. The app works without a network connection, and syncing happens in the background when connectivity exists.

Key principle: the user's device is the source of truth, not a remote server.

Cloud-First:    Device  -->  Server (authority)  -->  Device
Offline-First:  Device  -->  Cache locally  -->  Server when available
Local-First:    Device (authority)  <-->  Sync  <-->  Device (authority)

Cloud-First

  • Data lives on the server
  • App is a thin client rendering server state
  • Offline = broken
  • Examples: traditional SaaS, Google Docs (pre-offline), most web apps

Offline-First

  • Data cached locally for offline use
  • Server remains the authority
  • Conflicts resolved server-side (last-write-wins or manual)
  • Examples: Progressive Web Apps with service workers, mobile apps with local caches

Local-First

  • Data originates and lives on the device
  • Every device holds a full (or partial) replica
  • Sync is peer-to-peer or via relay servers
  • Conflicts resolved automatically via CRDTs or similar
  • Examples: Figma (hybrid), Linear (hybrid), Obsidian Sync, Anytype

Core Benefits

1. Instant User Experience

No loading spinners. No waiting for server round-trips. Every read and write hits local storage.

// Cloud-first: every action waits for the server
async function addTodo(text) {
  const response = await fetch('/api/todos', {
    method: 'POST',
    body: JSON.stringify({ text }),
  });
  // UI updates after server responds (200-500ms)
  return response.json();
}

// Local-first: write locally, sync in background
function addTodo(text) {
  // UI updates instantly (< 1ms)
  db.todos.add({ id: generateId(), text, done: false });
  // Sync happens automatically in the background
}

2. Offline Capability

The app works without any network connection. Users on planes, in subways, or in areas with poor connectivity have full functionality.

3. Data Ownership and Privacy

Data stays on the user's device. No vendor lock-in. Users can export, back up, and control their data. Sensitive information never has to touch a third-party server.

4. Resilience

If the server goes down, the app keeps working. If the company shuts down, the user still has their data. No single point of failure.

5. Collaboration Without Central Servers

Peer-to-peer sync allows real-time collaboration without routing through a central server. Devices on the same LAN can sync directly.


Core Challenges

1. Conflict Resolution

When two devices modify the same data offline, conflicts arise on sync.

Device A (offline): rename file to "report-v2.pdf"
Device B (offline): rename file to "final-report.pdf"
                         |
                    Both come online
                         |
                    Which name wins?

Strategies:

  • Last-Write-Wins (LWW): Simple but lossy. One edit is silently discarded.
  • CRDTs: Mathematically guarantee convergence without data loss. More complex.
  • Operational Transform (OT): Transforms operations relative to each other. Used by Google Docs. Requires a central server.
  • Manual resolution: Show conflicts to the user. Git-style.

2. Sync Complexity

Building a reliable sync engine is hard:

  • Partial sync (not all data on all devices)
  • Bandwidth optimization (don't re-send everything)
  • Ordering guarantees (causal consistency)
  • Schema evolution (what if devices run different app versions?)

3. Storage Limits

Browsers limit IndexedDB storage (varies by browser, typically 50% of disk up to a cap). Mobile devices have tighter constraints. Large datasets need strategies like pagination, eviction, and selective sync.

4. Security Model

When data lives on the device, encryption and access control must work locally:

  • End-to-end encryption for synced data
  • Local key management
  • Device authorization and revocation

Architectural Patterns

Pattern 1: CRDT-Based Document Sync

Best for: collaborative editing, shared workspaces.

┌──────────┐     ┌──────────┐     ┌──────────┐
│ Device A │     │  Relay    │     │ Device B │
│          │     │  Server   │     │          │
│ ┌──────┐ │     │           │     │ ┌──────┐ │
│ │ CRDT │◄├─────┤►  Merge  ◄├─────┤►│ CRDT │ │
│ │ Doc  │ │     │           │     │ │ Doc  │ │
│ └──────┘ │     │           │     │ └──────┘ │
│ ┌──────┐ │     └───────────┘     │ ┌──────┐ │
│ │ IDB  │ │                       │ │ IDB  │ │
│ └──────┘ │                       │ └──────┘ │
└──────────┘                       └──────────┘

Libraries: Yjs, Automerge, Loro

Pattern 2: Optimistic Mutations with Server Reconciliation

Best for: apps that need server-side validation and authorization.

┌──────────┐         ┌──────────┐
│  Client  │         │  Server  │
│          │         │          │
│ 1. Mutate├────────►│ 3. Apply │
│    locally│        │    or    │
│ 2. Queue │        │    reject │
│    mutation│       │ 4. Push  │
│          │◄────────┤    canonical│
│ 5. Rebase│         │    state │
│    local │         │          │
└──────────┘         └──────────┘

Libraries: Zero (Rocicorp), Replicache, PowerSync

Pattern 3: Event Sourcing with Local Log

Best for: apps where full history matters (finance, audit trails).

// Every change is an immutable event
const events = [
  { type: 'ITEM_ADDED', id: 'a1', name: 'Milk', ts: 1700000000 },
  { type: 'ITEM_CHECKED', id: 'a1', ts: 1700000060 },
  { type: 'ITEM_ADDED', id: 'a2', name: 'Bread', ts: 1700000120 },
];

// Current state is derived by replaying events
function deriveState(events) {
  return events.reduce((state, event) => {
    switch (event.type) {
      case 'ITEM_ADDED':
        return { ...state, [event.id]: { name: event.name, checked: false } };
      case 'ITEM_CHECKED':
        return { ...state, [event.id]: { ...state[event.id], checked: true } };
      default:
        return state;
    }
  }, {});
}

When to Use Local-First

Strong Fit

  • Collaborative editing: documents, whiteboards, design tools
  • Note-taking and personal knowledge management: Obsidian-like apps
  • Field work applications: data collection where connectivity is unreliable
  • Privacy-sensitive domains: health data, financial records, journaling
  • Real-time multiplayer: games, shared cursors, live collaboration
  • Developer tools: code editors, local databases, CLI tools

Weak Fit

  • Server-authoritative systems: banking transactions, inventory with strict consistency
  • Large dataset processing: analytics dashboards querying terabytes of data
  • Ephemeral content: feeds, timelines where data is consumed and discarded
  • Regulatory requirements: when data must live in specific server jurisdictions

Decision Checklist

[ ] Users need the app to work offline
[ ] Latency matters (instant responses expected)
[ ] Users want to own/control their data
[ ] Collaboration between devices or users is needed
[ ] Privacy is a core requirement
[ ] The dataset per user is manageable on-device (< few GB)
[ ] You can invest in sync infrastructure complexity

If 4+ boxes are checked, local-first is likely the right choice.


Getting Started: Minimal Local-First App

import * as Y from 'yjs';
import { IndexeddbPersistence } from 'y-indexeddb';
import { WebsocketProvider } from 'y-websocket';

// 1. Create a CRDT document
const doc = new Y.Doc();

// 2. Persist locally (works offline)
const localProvider = new IndexeddbPersistence('my-app', doc);

// 3. Sync with peers when online
const remoteProvider = new WebsocketProvider(
  'wss://my-sync-server.com',
  'my-room',
  doc
);

// 4. Use shared data types
const todos = doc.getArray('todos');

// This works offline, syncs when connected, merges without conflicts
todos.push([{ text: 'Buy groceries', done: false }]);

// 5. Observe changes (from local or remote)
todos.observe((event) => {
  renderTodoList(todos.toArray());
});

Key Terminology

TermDefinition
ReplicaA full or partial copy of the dataset on a device
CRDTConflict-free Replicated Data Type; merges without coordination
Sync engineThe layer that detects changes and propagates them between replicas
Optimistic updateApplying a mutation locally before server confirmation
Causal orderingEnsuring operations are applied in an order consistent with causality
TombstoneA marker indicating a deleted item (needed for sync)
Version vectorA data structure tracking the latest known state from each replica
Partial replicationSyncing only a subset of the full dataset to a device

Install this skill directly: skilldb add local-first-skills

Get CLI access →

Related Skills

crdt-fundamentals

Teaches Conflict-free Replicated Data Types (CRDTs), the mathematical foundation for local-first sync. Covers how CRDTs guarantee eventual consistency without coordination, the difference between state-based and operation-based CRDTs, and practical implementations of G-Counter, PN-Counter, LWW-Register, OR-Set, G-Set, and RGA (Replicated Growable Array). Includes causal ordering, vector clocks, and guidance on choosing the right CRDT for your data model.

Local First454L

electric-sql

Teaches ElectricSQL, a Postgres-backed local-first sync framework. Covers the Electric architecture where Postgres is the source of truth and data syncs to local SQLite databases on client devices via shape-based partial replication. Includes shape definitions, live queries, offline-first patterns, conflict resolution with rich CRDTs, integration with React and Expo (React Native), deployment patterns, and migration strategies.

Local First433L

indexeddb-patterns

Teaches IndexedDB patterns for local-first web applications, using Dexie.js as the primary wrapper library. Covers schema design and versioning, creating indexes for efficient queries, transaction patterns, performance optimization (bulk operations, pagination, lazy loading), migration strategies for schema evolution, storage quota management, data export and import, and integration patterns with sync engines and reactive frameworks.

Local First556L

local-first-auth

Teaches authentication and authorization patterns for local-first applications that must work offline. Covers offline-capable auth with cached tokens, permission sync and local enforcement, encrypted local storage for sensitive data, key management with device-bound keys, device authorization and revocation, multi-device identity linking, end-to-end encryption for synced data, and secure patterns for handling auth in disconnected environments.

Local First606L

sync-engine-architecture

Teaches how to design and build a sync engine for local-first applications. Covers the operation log as the foundation, conflict resolution strategies (last-write-wins, operational transform, CRDTs), server reconciliation patterns, partial sync for large datasets, bandwidth optimization techniques, version vectors and causal consistency, clock synchronization, and practical implementation patterns with code examples.

Local First572L

yjs-sync

Teaches building local-first collaborative applications with Yjs, the most widely adopted CRDT library for JavaScript. Covers the Y.Doc document model, shared types (Y.Map, Y.Array, Y.Text, Y.XmlFragment), the awareness protocol for presence and cursors, persistence and sync providers (WebSocket, WebRTC, IndexedDB), integrating with editors like ProseMirror/TipTap/CodeMirror/Monaco, undo/redo management, and performance optimization patterns.

Local First471L