localStorage and sessionStorage
Published Updated
In one line: localStorage and sessionStorage are synchronous, string-only,
same-origin key-value stores exposed on Window; localStorage persists across tabs and
browser restarts, while sessionStorage is scoped to one tab and cleared when that tab
closes.
Reading and writing
Section titled “Reading and writing”localStorage.setItem("theme", "dark");const theme = localStorage.getItem("theme"); // "dark"localStorage.removeItem("theme");localStorage.clear(); // removes every key for this origin
// sessionStorage has the identical method set, scoped to the current tab:sessionStorage.setItem("draftId", "42");Per MDN’s usage guide, both interfaces store only strings — non-string data such as
objects or arrays must be converted explicitly, for example with JSON.stringify().
Browser support and quota
Section titled “Browser support and quota”Both localStorage and sessionStorage are long-standing, widely implemented parts of
the Web Storage API across current browsers. Per MDN, the two are separate Storage
objects that “function and are controlled separately.” Per MDN’s usage guide, writes can
still fail once all available storage for the origin has been used, throwing a
QuotaExceededError DOMException rather than failing silently.
Reacting to changes from other tabs
Section titled “Reacting to changes from other tabs”window.addEventListener("storage", (event) => { console.log(event.key, event.oldValue, event.newValue);});The storage event fires on other Documents that share the same storage area when
localStorage changes — never on the document that made the change itself. Per MDN, this
means a same-origin document elsewhere in the same tab, such as an iframe, can still
receive the event even though the writing document does not. Use it to keep other open
documents in sync.
How to detect it at runtime
Section titled “How to detect it at runtime”function storageAvailable() { if (!('localStorage' in window)) { // localStorage property not present — fall back to an in-memory store for this session. return false; } try { const probe = "__storage_test__"; window.localStorage.setItem(probe, probe); window.localStorage.removeItem(probe); return true; } catch { // Present but unusable — e.g. a private-browsing mode that reports a 0-byte // quota — so treat it as unavailable and fall back the same way. return false; }}This mirrors MDN’s own feature-detection guidance in “Using the Web Storage API,” which
also probes with a real write — though MDN’s version treats a QuotaExceededError on an
already non-empty store as evidence storage is still available, rather than
unconditionally reporting failure the way the simplified probe above does.
What goes wrong
Section titled “What goes wrong”- Values are always strings —
JSON.stringify()beforesetItem()andJSON.parse()aftergetItem()for anything structured. - Both stores are same-origin: scheme, host, and port must all match, so
https://example.comandhttp://example.comdo not share storage. - The
storageevent only fires on other documents sharing the storage area, never on the document that made the write — do not wait for it locally. Per MDN, a same-origin document elsewhere in the same tab (e.g. an iframe) can still receive it. - Private/incognito behavior is not uniform across browsers. Per MDN’s Web Storage
guide, data written in a private window is generally treated like
sessionStorageand cleared when the last private tab closes — but MDN also notes that some browsers instead expose alocalStorageobject with a fixed 0-byte quota, so writes throw immediately rather than surviving until the tab closes. Feature-detect with a real write/remove probe rather than assuming either behavior. - All writes and reads are synchronous and run on the main thread; large values or frequent writes can block rendering — prefer IndexedDB for anything sizable.
-
sessionStorageis partitioned by both origin and top-level browsing context, per MDN — not simply one store per tab. Per MDN, a newly opened page that has anopenerreference back to the page that opened it initially receives a copy of that opener’ssessionStorage; a context opened without an opener does not.
Where to go next
Section titled “Where to go next”- Storage persistence, quotas, and eviction — the related reference on origin storage quotas.
- Clearing site data — the related reference on clearing storage for a site.