Offline-first PWAs need two paths: read paths that keep the UI useful, and write paths that make retries safe.
sequenceDiagram
participant U as User
participant App as Web app
participant IDB as IndexedDB
participant SW as Service worker
participant API as API
U->>App: Open app
App->>IDB: Read local state
App-->>U: Render immediately
App->>SW: Fetch fresh data
SW->>API: Network request
alt network succeeds
API-->>SW: Fresh response
SW-->>App: Response
App->>IDB: Merge data
else offline
SW-->>App: Cached or fallback response
end
U->>App: Create mutation
App->>IDB: Store queued write
App-->>U: Show pending state
App->>API: Try send now
alt send succeeds
API-->>App: Accepted
App->>IDB: Mark synced
else send fails
App->>IDB: Keep queued write
end
Design Rules
Rule
Why
Render from local data first
Offline and slow networks still feel usable
Store writes before sending
You do not lose user work when the network drops
Make mutation IDs idempotent
Replays should not duplicate business records
Keep queue state visible
Users need to know what is pending, failed, or synced
Provide manual retry/export
Background APIs are not universal
Cache Versus Data
Need
Use
App shell assets
Precache or versioned Cache Storage
Offline fallback page
Cache Storage through service worker fallback
API responses safe to reuse
Runtime caching with expiration and invalidation rules