Browser Storage Methods: Storage API vs IndexedDB vs Cookies
Alex | Last updated: April 15, 2024
Modern web browsers provide three main ways of client storage:
- Web Storage Api (Local/Session Storage)
- IndexedDB
- Cookies
Web Storage API
The conventional client storage solution has long been the Web Storage API. There are two mechanisms for Web Storage:
sessionStorage
maintains storage data so long as a page session is active;sessionStorage
data survives page reloads, but not browser tab/window closures.localStorage
maintains storage data until said data is explicitly deleted;localStorage
data survives page reloads and browser tab/window closures.
The Storage API is useful for storing non-sensitive data for use within client scripts, such as user settings in localStorage
—sessionStorage
can be used to temporarily store usernames and passwords, though some might advise against this. Data is stored as key-value pairs, which makes primitive data easy to read and write.
While the base API is easy to work with, the Web Storage API only accepts strings as values; to store anything more complicated, such as a JSON
object, one must stringify
the object before storing it and parse
the object when retrieving it. This also means the developer must manually encode a versioning schema and write custom migration logic for anything more complicated than primitive strings to prevent data corruption issues. It’s a pain.
WebStorage generally has a storage limit of 5mbs. Moreover, Web Storage is synchronous in nature. Writing and reading from Web Storage will block the main thread and prevent other JavaScript code until complete. Web Storage is also not available for use from within Web Workers. There are also potential security issues regarding CORS and a client’s ability to trivially tamper with stored values. Sad.
In modern web development, the Web Storage API has largely been replaced by IndexedDB; if you want to store anything more complicated than key-value pairs, use IndexedDB.
IndexedDB
Why IndexedDB is Great
IndexedDB is a great client storage solution, and it is my preferred method of storing things locally—sans auth. IndexedDB
- Allows client storage, querying of, and indexing of binary data, which means one can store structured data and complex objects (such as JSON objects with nested schemas, files, and blobs) without hassle.
- Makes it easy to implement versioning and migration logic (most if it is handled for you)—so long as you correctly assign and increment version numbers in your code—so you do not need to worry about data corruption issues.
- IndexedDB works asynchronously, so it doesn’t clog up the main thread.
- Is usable from within Web Workers, unlike the Storage API.
- Has a much larger storage cap than other client storage solutions.
IndexedDB’s Shortcomings
In my experience working with IndexedDB so far, there aren’t too many shortcomings other than:
- When developing, when you make schema changes, you must remember to increment the version number in your code. (This is also something you need to worry about for other databse solutions like Atlas Realm)
- Backwards compatability: Some older browsers do not support IndexedDB, but this is the case for some other features too, like WebSockets and Server-Sent Events.
- Its API is more complicated than Session Stoarge and Cookies, but several libraries exist to alleviate the potential pains of working with IndexedDB.
Ways to Work with IndexedDB
If you want to avoid using the out-of-the-box native IndexedDB API, there are two popular options:
- idb (GitHub): “IndexedDB with usability.” I prefer this one, and there is a pretty helpful guide to working with the IndexedDB Promised library.
- Dexie (npm, GitHub): Wrapper with more robust features, such as Sync.
Cookies
Browser cookies are meant to be small pieces of data a server sends to a user’s web browser to be used for later server requests. They are most commonly used for user authentication/access persistence and tracking.
Cookies can be made relatively safe against Cross-Site Scripting (XSS) by setting the HTTP only flag to true—this prevents JavaScript from accessing cookies, which is fine as cookies are mainly used to preserve authentication for network requests and read server-side—and imposing an expiration date. However, without SSL encryption, they are susceptible to being intercepted on open networks. As with the Storage API, cookies are also susceptible to being tampered with by the client.
Of all the browser storage solutions, cookies are the most restricted in terms of storage space:
- A client may only have 300 total cookies.
- Cookies have a maximum siez of 4096 bytes.
- Each domain may only store 20 cookies max.
All cookies valid for a given page on a given domain are sent from the browser to the server for every request to the same domain.
Summary
Web Storage API | IndexedDB | Cookies | |
---|---|---|---|
Storage Values | Key-value pairs restricted to strings only. | Allows for storage, advanced querying, and indexing of complex objects. | Key-value pairs restricted to strings only, alongside attributes that control when and where the cookie is used. |
Storage Limits | 5MB storage limit. | Storage limit determined by client storage availability. | 300 max cookies for the browser—20 per domain, and 4096 bytes per cookie. |
Operations | Operations are synchrounous, single-threaded, and blocking. | Operations are asynchrounous. | Operations are synchrounous, single-threaded, and blocking. |
Complex Objects | Possible to store complex objects using JSON methods, but versioning and migration logic must be custom and often complex. | Versioning and migration largely handled out of the box. | Complex object storage not practical, given storage limitations. |
Client Tampering | Difficult to prevent trivial tampering by user. | Read-only from browser, sans delete operations. | Difficult to prevent trivial tampering by user. |
Security Vulnerabilities | Vulnerable to XSS. | Vulnerable to XSS. | Vulnerable to data interception. |