Database

Session Storage: Limitations and TypeScript Usage

Session storage lets you store data in the browser that survives page reloads but disappears when the tab closes. It's useful, but its limitations trip pe...

7 May 2024

Session Storage: Limitations and TypeScript Usage

Session storage lets you store data in the browser that survives page reloads but disappears when the tab closes. It's useful, but its limitations trip people up.

What Session Storage Does

It stores key-value pairs scoped to a single browser tab. Each tab gets its own isolated storage. Data persists through page reloads and navigation within the same tab, but vanishes the moment the user closes that tab.

The Limitations

Tab-scoped, not window-scoped. Open two tabs to the same site? They don't share session storage. This confuses users who expect state to sync across tabs. If your app depends on shared state, session storage is the wrong tool.

Strings only. Everything goes in and comes out as a string. Objects and arrays need to be serialized.

5-10 MB limit. Browsers allocate roughly 5-10 MB per origin. That's enough for UI state and small datasets. Not enough for caching large API responses.

Same-origin policy. Data is only accessible from the same protocol + hostname + port combination that wrote it. No cross-origin access.

Synchronous API. All reads and writes block the main thread. With large data, this can cause jank.

Using Session Storage in TypeScript

Basic read and write:

Typescript
sessionStorage.setItem('username', 'JohnDoe');

const username = sessionStorage.getItem('username');

Storing objects requires serialization:

Typescript
interface UserPreferences {
  theme: 'light' | 'dark';
  language: string;
  notifications: boolean;
}

function savePreferences(prefs: UserPreferences): void {
  sessionStorage.setItem('preferences', JSON.stringify(prefs));
}

function loadPreferences(): UserPreferences | null {
  const raw = sessionStorage.getItem('preferences');
  if (!raw) return null;
  return JSON.parse(raw) as UserPreferences;
}

A type-safe wrapper to handle the serialization cleanly:

Typescript
class TypedSessionStorage<T> {
  constructor(private key: string) {}

  get(): T | null {
    const raw = sessionStorage.getItem(this.key);
    if (!raw) return null;
    try {
      return JSON.parse(raw) as T;
    } catch {
      return null;
    }
  }

  set(value: T): void {
    sessionStorage.setItem(this.key, JSON.stringify(value));
  }

  remove(): void {
    sessionStorage.removeItem(this.key);
  }
}

const cartStorage = new TypedSessionStorage<string[]>('cart');
cartStorage.set(['item-1', 'item-2']);
const cart = cartStorage.get();

When to Use It

Session storage works well for temporary UI state: form progress that should survive a page reload, one-time wizard flows, or per-tab feature flags.

Don't use it for anything that needs to persist beyond the session, sync across tabs, or survive a browser crash. For those cases, use localStorage, IndexedDB, or server-side sessions.

Keep reading