How Firefox Implements IndexedDB for Client-Side Storage

This article explores the internal architecture of the Mozilla Firefox web browser and how it implements the IndexedDB standard for client-side storage. It covers the underlying SQLite database engine used to power the NoSQL API, the inter-process communication (IPC) required for security, data serialization methods, and how the browser manages disk quotas and transactions.

SQLite as the Underlying Storage Engine

Although the IndexedDB specification defines a NoSQL, transactional, key-value object store, Firefox implements it on top of a relational database management system: SQLite. For every IndexedDB database created by a web application, Firefox generates a corresponding SQLite database file on the user's local hard drive.

The browser maps IndexedDB concepts directly to relational tables. For instance, internal SQLite tables are generated to track database metadata, object stores, and indexes. By translating IndexedDB API calls into SQL queries under the hood, Mozilla leverages SQLite’s proven reliability, ACID compliance (Atomicity, Consistency, Isolation, Durability), and crash recovery mechanisms rather than building and maintaining a custom database engine from scratch.

Multi-Process Architecture and IPC

Firefox utilizes a multi-process architecture that separates untrusted web content from the core browser system for security and stability. Web pages run in sandboxed "content processes" that are forbidden from directly accessing the user's file system. Consequently, IndexedDB operations must cross process boundaries.

When a web application executes an IndexedDB request, the content process sends an asynchronous message to the privileged "parent process" using Firefox's Inter-Process Communication (IPC) layer. Specifically, it uses a dedicated background mechanism known as PBackground. This ensures that the heavy lifting of message routing and disk Input/Output (I/O) happens entirely off the main user interface thread, preventing the browser from freezing while large datasets are read or written.

Data Serialization and File Handling

SQLite cannot natively store raw JavaScript objects. To store data, Firefox first serializes the JavaScript objects in the content process using the HTML5 Structured Clone Algorithm. This converts complex objects—such as Maps, Sets, Dates, and nested arrays—into a flat binary array. To save disk space and improve I/O speed, Firefox compresses this binary data using the Snappy compression library before sending it over IPC to be written into the SQLite database.

Large binary objects, such as Blob or File instances, are treated differently to prevent the SQLite database from becoming bloated and slow. Firefox intercepts these files and writes them directly to the local file system in a dedicated directory alongside the database. The SQLite database only stores a lightweight reference pointer to the external file, which is seamlessly reconnected when the web application requests the data back.

The Quota Manager and Origin Isolation

All IndexedDB files are stored within the user's Firefox profile directory and are strictly segregated by the web application's origin (the combination of protocol, domain, and port) to enforce the Same-Origin Policy.

Disk space for these files is governed by Firefox's Quota Manager. This unified system tracks and limits storage usage across IndexedDB, the Cache API, and LocalStorage. Firefox enforces both a global limit (a percentage of available disk space) and a per-origin limit. By default, IndexedDB data is classified as "best-effort" temporary storage. If the user's hard drive runs critically low on space, the Quota Manager uses a Least Recently Used (LRU) policy to automatically delete the oldest origin data, ensuring web applications cannot exhaust the host system's storage.

Transactions and Concurrency

The IndexedDB standard dictates strict rules for data access through three transaction types: readonly, readwrite, and versionchange. Firefox manages these in the parent process using a dedicated thread pool for database I/O.

Firefox allows multiple readonly transactions on the same object store to execute concurrently, maximizing performance for data retrieval. However, if a web app initiates multiple readwrite transactions that target overlapping object stores, Firefox queues them and executes them sequentially to prevent race conditions and data corruption. A versionchange transaction, which is used to create or delete object stores and indexes, acts as an exclusive lock, blocking all other transactions on that database until the schema modification is fully committed to the SQLite file.