← Docs
Recipe

localStorage Patterns

Reliable client-side persistence with error handling, quota awareness, and structured data.

Safe Wrapper

Always wrap getItem and setItem in try/catch. Private browsing and storage quotas throw synchronous errors.

function safeGet(key, fallback = null) {
  try {
    const v = localStorage.getItem(key);
    return v === null ? fallback : v;
  } catch { return fallback; }
}

JSON with Schema Guard

Parse with a version field so stale schemas don't corrupt state on deploy.

function readJSON(key, schemaVersion = 1) {
  const raw = safeGet(key);
  if (!raw) return null;
  try {
    const parsed = JSON.parse(raw);
    return parsed._v === schemaVersion ? parsed : null;
  } catch { return null; }
}

Quota Eviction

On QuotaExceededError, evict oldest keys by a stored timestamp prefix.

function setWithEvict(key, value) {
  try {
    localStorage.setItem(key, value);
  } catch (e) {
    if (e.name === 'QuotaExceededError') {
      const keys = Object.keys(localStorage)
        .filter(k => k.startsWith('_ts:'))
        .sort((a, b) => +localStorage.getItem(a) - +localStorage.getItem(b));
      for (const k of keys.slice(0, 5)) localStorage.removeItem(k);
      localStorage.setItem(key, value);
    }
  }
}

Meridian tip: Prefix all keys with your app namespace (mdrn:) to avoid collisions with third-party scripts on the same origin.