Skip to content

Cache API vs IndexedDB vs localStorage

The browser offers three main client-side storage APIs for persistent data. They serve different purposes and complement each other — the key is picking the right one for each use case.

StorageBest forData typeAsync?Approximate size
Cache APIHTTP responses, static assetsRequest/ResponseYesLarge (GBs possible)
IndexedDBStructured app data, offline recordsJS objects, blobsYesLarge (GBs possible)
localStorageTiny config strings, UI preferencesString onlyNo (synchronous)~5 MB

The Cache API stores Request/Response pairs. It is shaped like HTTP — the key is a URL (or Request object) and the value is a Response. This makes it ideal for:

  • Pre-caching static assets (HTML, CSS, JS, images) for offline use
  • Runtime caching of API responses inside a Service Worker
  • Serving stale content while a fresh version is fetched in the background

The Cache API is most useful in combination with a Service Worker. See the PWA course for Service Worker caching patterns.

IndexedDB stores arbitrary JavaScript values (objects, arrays, blobs, typed arrays) in object stores with optional indexes. It is the right choice for:

  • Offline app data: user records, messages, documents
  • Large blobs: audio, video, images that are part of the app’s data model
  • Data that needs to be queried, sorted, or filtered client-side
  • Any structured data that does not fit the URL-keyed HTTP model

localStorage stores string key/value pairs synchronously. It blocks the main thread on every read and write. Despite its convenience, it is only suitable for:

  • Tiny preferences: theme choice, language, a single token
  • Values read on every page load where the synchronous access is acceptable
  • Anything under a few kilobytes

Never store large objects or do frequent writes in localStorage — it will stall rendering.

flowchart TD
  Q[What do you need to store?]
  Q --> A{HTTP responses
or assets?}
  A -->|Yes| CacheAPI[Cache API
caches.open / put / match]
  A -->|No| B{Structured
app data?}
  B -->|Yes| IDB[IndexedDB
object stores + indexes]
  B -->|No| C{Tiny string
preference?}
  C -->|Yes| LS[localStorage
setItem / getItem]
  C -->|No| IDB
Storage decision: HTTP responses → Cache API, structured data → IndexedDB, tiny strings → localStorage
Which storage API is purpose-built for caching HTTP responses and static assets?
Which storage API blocks the main thread on every read and write?
You need to store a large array of user messages for offline access, with the ability to query by date. Which API should you use?
Which storage API would you choose to cache JS and CSS bundles for a PWA that must work offline?