Skip to main content

Side by side

IndexedDBvsLocal Storage

What is the difference between IndexedDB and localStorage?

Updated 3 min read8 differences

In short

localStorage is a small, synchronous store of strings; IndexedDB is an asynchronous browser database for large structured data and files.

IndexedDB

Indexed Database API

IndexedDB is a database built into web browsers that stores large amounts of structured data and files on the user's device, with indexes and transactions.

Read the page on IndexedDB

Local Storage

Local storage is a browser feature that lets a website save text as key-value pairs on the user's device, where it stays even after the browser is closed.

Read the page on Local Storage

IndexedDB and Local Storage compared

AspectIndexedDBLocal Storage
TypeA full database with object stores, indexes and transactionsA simple key-value store
Data storedObjects, arrays, dates and files, without conversionStrings only; objects go through JSON.stringify
CapacityOften hundreds of megabytes or more, depending on free diskAbout 5 MB per origin
API styleAsynchronous: requests with events, or promises through a wrapperSynchronous: each call blocks the page until it finishes
LookupsBy key, by index ranges and with cursorsBy exact key only
TransactionsYes; a group of writes succeeds or fails as a wholeNone; each setItem stands alone
In workersAvailable in web workers and service workersOnly in the page itself, not in workers
Best forOffline data, cached API responses, large lists, filesSmall settings: theme, language, flags, a short draft

The difference, explained

Both keep data in the browser, on the user's device, separately for each origin. localStorage is a simple key-value store: strings under string keys, written with setItem and read with getItem. IndexedDB is a full database built into the browser: object stores hold JavaScript objects under keys, indexes find records by other fields, and transactions group writes that either all succeed or all fail.

The essential differences are size, data model and timing. localStorage is limited to about 5 MB per origin, stores only strings, so objects pass through JSON.stringify, and its calls are synchronous, blocking the page while they run. IndexedDB can usually use a large share of the free disk, stores objects, dates and files directly, and is asynchronous, so big reads and writes don't freeze the interface. It also works in web workers and service workers, where localStorage is not available.

Many apps that use IndexedDB use localStorage as well. A theme, a language or a feature flag is a few bytes that the page wants at once, so localStorage is simpler; an offline mailbox, cached API responses or a list of thousands of drafts belongs in IndexedDB. The raw IndexedDB API is verbose and event-based, so many projects use a small wrapper such as idb, which adds promises, or Dexie.js.

A common misconception is that IndexedDB is a SQL database in the browser. It has no tables or queries, only keys, indexes and cursors that step through records. Another is that either store is permanent or private: browsers may clear both when space runs low unless navigator.storage.persist() is granted, and any script on the page, including one injected through XSS, can read both.

Which one should you use?

Choose IndexedDB when…

  • You store a lot of data, such as an offline copy of records or files.
  • You need to look records up by fields other than the key.
  • Several writes must succeed or fail together.
  • A web worker or service worker needs the data.

Choose Local Storage when…

  • You store a few small values, such as a theme or a dismissed banner.
  • The page must read the value at once, for example to apply a theme before the first paint.
  • Simplicity matters more than capacity or structure.

Saving data each way (JavaScript)

IndexedDBjavascript
// IndexedDB, here through the small idb wrapper: objects, indexes, async
import { openDB } from "idb";

const db = await openDB("mail", 1, {
  upgrade(db) {
    const store = db.createObjectStore("messages", { keyPath: "id" });
    store.createIndex("byDate", "receivedAt");
  },
});
await db.put("messages", { id: 7, subject: "Hi", receivedAt: new Date() });
const byDate = await db.getAllFromIndex("messages", "byDate");
Local Storagejavascript
// localStorage: strings only, synchronous, no indexes
const prefs = { theme: "dark", fontSize: 16 };
localStorage.setItem("prefs", JSON.stringify(prefs));

const saved = JSON.parse(localStorage.getItem("prefs") ?? "{}");
saved.theme; // "dark", available at once, no await

Readers ask

How much more can IndexedDB store than localStorage?

Much more. localStorage stops at about 5 MB per origin, while IndexedDB shares the origin's storage quota, which in modern browsers is often hundreds of megabytes or more; navigator.storage.estimate() reports the actual figure.

Is localStorage faster than IndexedDB?

For one small value, reading localStorage is quick and needs no await. For many or large records it is worse, because every call blocks the page, while IndexedDB works asynchronously and can fetch just the records an index points to.

Can I use IndexedDB in a service worker?

Yes, and it is the usual place for offline data there. localStorage is not available in service workers or in other web workers.

More

Settings