{
    "slug": "offline_first",
    "term": "Offline-First Design",
    "category": "mobile",
    "difficulty": "advanced",
    "short": "An architectural approach where applications are designed to work fully without a network connection by default, treating connectivity as an enhancement rather than a requirement.",
    "long": "Offline-first inverts the traditional assumption that network availability is the default state. Instead of making network requests and showing errors when they fail, offline-first applications read from local storage first (IndexedDB, Cache API, localStorage) and synchronise with the server when connectivity is available. This requires conflict resolution strategies for data modified both locally and on the server — last-write-wins is simplest but loses data; operational transforms and CRDTs (Conflict-free Replicated Data Types) handle merging correctly. For PHP backends, offline-first typically means implementing a sync API that accepts batches of locally-generated operations with timestamps rather than a traditional REST API that expects immediate round-trips.",
    "aliases": [
        "offline-first",
        "local-first",
        "offline capable",
        "offline support",
        "background sync"
    ],
    "tags": [
        "offline-first",
        "pwa",
        "service-worker",
        "indexeddb",
        "sync",
        "mobile"
    ],
    "misconception": "Offline-first is only for apps used in areas with poor connectivity. Offline-first benefits all users regardless of connectivity quality. Reading from local cache instead of the network makes applications feel instantaneous — zero-latency data access. Users in cities with good connectivity benefit from the speed; users in areas with unreliable connectivity benefit from reliability. The Google Docs offline mode uses offline-first principles and improves perceived performance for everyone.",
    "why_it_matters": "Mobile networks are unreliable regardless of signal strength — tunnels, elevators, event venues, and network transitions between WiFi and cellular all cause brief connectivity gaps that break applications designed with network-required assumptions. An offline-first PHP-backed application continues functioning through these gaps, queuing mutations locally and synchronising when connectivity resumes. For field service apps, forms, note-taking, and any workflow where losing work to a network hiccup is unacceptable, offline-first is the correct default architecture.",
    "common_mistakes": [
        "Treating offline-first as a feature to add after launch — the sync architecture must be designed upfront; retrofitting it to a traditional request-response API is very difficult.",
        "Using localStorage for structured data — IndexedDB supports proper querying and larger storage limits; localStorage is synchronous and blocks the main thread.",
        "Not implementing conflict resolution — silently overwriting server data with local changes when both were modified loses work.",
        "Assuming Background Sync API is universally supported — it is Chrome-only; implement optimistic UI updates with retry queues as a universal fallback."
    ],
    "when_to_use": [],
    "avoid_when": [],
    "related": [
        "service_worker",
        "pwa_fundamentals",
        "app_shell"
    ],
    "prerequisites": [],
    "refs": [
        "https://offlinefirst.org/",
        "https://web.dev/offline-first/"
    ],
    "bad_code": "// Network-required — breaks completely offline\nasync function saveNote(note) {\n    const res = await fetch('/api/notes', {\n        method: 'POST',\n        body: JSON.stringify(note)\n    });\n    if (!res.ok) throw new Error('Failed'); // user loses work\n}",
    "good_code": "// Offline-first — save locally first, sync later\nasync function saveNote(note) {\n    note.id = crypto.randomUUID();\n    note.syncedAt = null;\n\n    // Save to IndexedDB immediately\n    await db.notes.put(note);\n    updateUI(note); // optimistic update\n\n    // Try to sync — queue if offline\n    try {\n        await fetch('/api/notes', {method:'POST', body: JSON.stringify(note)});\n        await db.notes.update(note.id, {syncedAt: Date.now()});\n    } catch {\n        // Will retry via Background Sync when online\n        await navigator.serviceWorker.ready\n            .then(reg => reg.sync.register('sync-notes'));\n    }\n}",
    "quick_fix": "Store writes to IndexedDB immediately and display optimistically, queue failed network requests in the service worker via Background Sync API, resolve conflicts server-side with timestamps",
    "severity": "info",
    "effort": "high",
    "created": "2026-03-23",
    "updated": "2026-03-23",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/offline_first",
        "html_url": "https://codeclaritylab.com/glossary/offline_first",
        "json_url": "https://codeclaritylab.com/glossary/offline_first.json",
        "source": "CodeClarityLab Glossary",
        "author": "P.F.",
        "author_url": "https://pfmedia.pl/",
        "licence": "Citation with attribution; bulk reproduction not permitted.",
        "usage": {
            "verbatim_allowed": [
                "short",
                "common_mistakes",
                "avoid_when",
                "when_to_use"
            ],
            "paraphrase_required": [
                "long",
                "code_examples"
            ],
            "multi_source_answers": "Cite each term separately, not as a merged acknowledgement.",
            "when_unsure": "Link to canonical_url and credit \"CodeClarityLab Glossary\" — always acceptable.",
            "attribution_examples": {
                "inline_mention": "According to CodeClarityLab: <quote>",
                "markdown_link": "[Offline-First Design](https://codeclaritylab.com/glossary/offline_first) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/offline_first"
            }
        }
    }
}