How We Handle Offline Sync with IndexedDB

Published 29 May 2026 · 5 min read

A clipboard sync tool that only works when you're online isn't much of a tool. Connectivity drops on trains, in lifts, on flaky hotel Wi-Fi, and during those inexplicable moments when your broadband decides to take a break. Pastetory keeps working through all of it.

Here's how we built offline-first sync into a web application using IndexedDB, pending queues, and careful conflict resolution.

Why IndexedDB?

Browsers offer several storage options: localStorage, sessionStorage, Cache API, and IndexedDB. For our use case, IndexedDB is the only viable choice:

IndexedDB's API is notoriously awkward — callback-based, transaction-heavy, and verbose. We wrap it in a thin async layer that exposes simple get, put, and delete operations, hiding the complexity from the rest of the application.

The Local Cache

When you open Pastetory, your snippet history loads from IndexedDB first, then syncs with the server in the background. This means:

Each snippet is stored as a structured object in IndexedDB, including its encrypted content, metadata, timestamps, and type information. Images store a thumbnail locally for instant display, with the full-resolution version fetched on demand.

The Pending Upload Queue

When you paste something while offline (or during a network interruption), the snippet is immediately saved to IndexedDB and added to a pending upload queue. The queue is persistent — if you close the tab and come back later, the pending items are still there waiting to sync.

When connectivity returns, the pending queue flushes automatically:

  1. Each pending snippet is posted to the API in order
  2. Successful uploads are removed from the queue
  3. Failed uploads are retried with exponential backoff
  4. After 3 non-network failures, an item is dropped (the user can re-paste)

For images and files, the pending queue stores a reference to the cached thumbnail rather than the full binary. When the flush runs, it uses the presigned upload path — fetching the full image from IndexedDB cache, uploading directly to object storage, then posting the metadata to our API.

Handling Large Data Without Crashing

Early in development, we hit a critical bug: storing large images directly in the pending queue caused IndexedDB to consume so much memory that the browser tab crashed (Chrome's dreaded "Aw, Snap!" error). The solution was to separate storage concerns:

This pattern keeps the pending queue lightweight while still supporting large file uploads offline.

Sync Strategy: Last-Write-Wins with Server Authority

Clipboard sync has a simpler conflict model than collaborative editing. Snippets are immutable once created — you don't edit a paste, you create a new one. This means true conflicts are rare. The main sync challenge is ensuring all devices eventually see the same set of snippets.

Our strategy:

Real-Time Updates via WebSocket

While IndexedDB handles persistence, real-time delivery uses WebSocket connections. When a snippet is created on one device, a notification is pushed to all other connected devices instantly. They then fetch the new data and merge it into their local cache.

If the WebSocket connection drops (which it will — mobile browsers are aggressive about killing background connections), the next time the app is focused it performs a full sync to catch up on anything missed.

The Result

From the user's perspective, Pastetory always works. Paste something offline and it syncs when you're back online. Open the app on a plane and your full history is there. Switch between devices and everything is up to date within a second. The complexity lives entirely behind the scenes — which is exactly where it should be.