FrontendAtlas
Interview Questions
Home>JavaScript interview questions> JavaScript coding challenges >Storage TTL Cache (localStorage/sessionStorage)

Storage TTL Cache (localStorage/sessionStorage)

intermediate
By FrontendAtlas Editorial · Updated Feb 3, 2026
Implement createTtlStorage(storage, now?) that returns { set, get, remove }. It should store JSON values with an optional TTL and automatically expire items when read. This mirrors real-world caching layers on top of localStorage/sessionStorage.

Arguments

  • storage: { getItem, setItem, removeItem } — A Storage-like object (localStorage/sessionStorage compatible).
  • now: () => number — Optional time provider (defaults to Date.now) for testing.

Returns

{ set: (key, value, ttlMs?) => void, get: (key) => any, remove: (key) => void } — A tiny TTL-aware cache wrapper.
Examples
const cache = createTtlStorage(localStorage);
cache.set('user', { id: 1 }, 5000);
cache.get('user');

cache.set('perm', 'ok'); // no expiry

Solution

Overview

Store a JSON envelope { v, exp } where exp is the absolute expiration timestamp or null. On get, parse the envelope, check exp, and delete expired or invalid entries.

1

Approach: JSON envelope with exp timestamp

Steps:

1) Validate that storage has getItem/setItem/removeItem.

2) set(): store JSON { v: value, exp: ttlMs == null ? null : now()+max(ttlMs,0) }.

3) get(): read, JSON.parse, and return v if exp is null or in the future; otherwise remove and return null.

4) If JSON.parse fails, remove the key and return null.

Complexity: O(1) per operation.

export default function createTtlStorage(storage, now = () => Date.now()) {
  if (!storage || typeof storage.getItem !== 'function') {
    throw new TypeError('storage must implement getItem/setItem/removeItem');
  }

  const set = (key, value, ttlMs) => {
    const exp = ttlMs == null ? null : now() + Math.max(0, ttlMs);
    const payload = JSON.stringify({ v: value, exp });
    storage.setItem(String(key), payload);
  };

  const get = (key) => {
    const raw = storage.getItem(String(key));
    if (raw == null) return null;
    try {
      const data = JSON.parse(raw);
      if (!data || !('v' in data)) return null;
      if (data.exp != null && now() >= data.exp) {
        storage.removeItem(String(key));
        return null;
      }
      return data.v;
    } catch {
      storage.removeItem(String(key));
      return null;
    }
  };

  const remove = (key) => {
    storage.removeItem(String(key));
  };

  return { set, get, remove };
}
type StorageLike = {
  getItem: (key: string) => string | null;
  setItem: (key: string, value: string) => void;
  removeItem: (key: string) => void;
};

export default function createTtlStorage(
  storage: StorageLike,
  now: () => number = () => Date.now()
) {
  if (!storage || typeof storage.getItem !== 'function') {
    throw new TypeError('storage must implement getItem/setItem/removeItem');
  }

  const set = (key: string, value: any, ttlMs?: number) => {
    const exp = ttlMs == null ? null : now() + Math.max(0, ttlMs);
    const payload = JSON.stringify({ v: value, exp });
    storage.setItem(String(key), payload);
  };

  const get = (key: string) => {
    const raw = storage.getItem(String(key));
    if (raw == null) return null;
    try {
      const data = JSON.parse(raw) as { v?: any; exp?: number | null };
      if (!data || !('v' in data)) return null;
      if (data.exp != null && now() >= data.exp) {
        storage.removeItem(String(key));
        return null;
      }
      return data.v;
    } catch {
      storage.removeItem(String(key));
      return null;
    }
  };

  const remove = (key: string) => {
    storage.removeItem(String(key));
  };

  return { set, get, remove };
}

Notes & Pitfalls

Pitfalls
  • Forgetting to remove expired entries can leave stale data forever.
  • Not handling JSON.parse errors can crash reads on corrupted storage.
  • Using localStorage for sensitive data is risky (it’s readable by JS).
Edge cases
  • ttlMs omitted: item should persist until explicitly removed.
  • ttlMs = 0 or negative: item expires immediately.
  • Missing keys should return null.
Techniques
  • JSON envelope storage.
  • Time-based expiry checks.
  • Defensive parsing + cleanup.

Resources

  • MDN – Web Storage API

Similar questions

Fetch JSON with Timeout + AbortintermediateMemoizationintermediateQuerystring Helper 2: Implement `stringifyQueryString`intermediate

Guides

Frontend interview preparation guideGuideFrontend coding interview questions and prep guideBlueprintJavaScript Problems That Actually Show UpBlueprintBuild Great UI in 60 MinutesBlueprint

Preparing for interviews? Use Frontend Coding Challenges first, then move into a concrete Study Plan before targeted Company Prep.

Open frontend interview questionsBrowse JavaScript interview questionsOpen Essential 60Open Machine Coding HubOpen Frontend Coding ChallengesOpen System DesignOpen Interview Prep GuideOpen System Design BlueprintOpen Framework Prep PathsOpen Study PlansOpen JavaScript mastery study planOpen Company PrepOpen JavaScript Framework Prep Guide
↗Incidents hub
69 / 88Next →→