Skip to content

Package overview

Namespace it. Expire it. Upgrade it — without localStorage glue.

Persist app data in the browser — with namespaces, expiry, and schema upgrades — without reinventing localStorage helpers.

Think of Storage as a small policy layer on top of an adapter you choose (memory, localStorage, sessionStorage, or IndexedDB). You call set / get; Storage wraps values in an envelope (metadata + your data).

Start here

New to the package?Tutorial (10 minutes)
Know localStorage already? → skim Core concepts, then Recipes
Need the full API?Core · TypeDoc

In one minute

ts
import { createStorage, createLocalStorageAdapter } from "@jayoncode/storage";

const storage = createStorage({
  namespace: "app", // all keys live under "app:…"
  adapter: createLocalStorageAdapter(),
});

storage.set("theme", "dark");
storage.get("theme"); // "dark" | null

That is enough for many apps. Everything else (TTL, policies, migrate, cleanup, …) is optional.

Try it in the Lab →

Pick your path

You are…Read thisThen
Beginner — first time using StorageTutorialConceptsRecipes
Shipping an app — prefs, cache, SSRCore · ErrorsBest practices · Browser support
Advanced — GC, backup, events, IDB, cross-tab, quotaMaintenanceQuota · TransformsComposition

When to use

  • Theme / UI prefs that should survive reload
  • Short-lived cache next to longer-lived prefs
  • Explicit backends: memory in tests, localStorage in the browser
  • Optional: cleanup expired keys, export/import, in-process watchers, same-tab transactions

When not to use

NeedUse instead
Live UI state (React/Vue store)Your framework state
Form draft UXForm Intelligence
Queryable / relational IndexedDB@jayoncode/storage/async is key/value IDB — not a query engine
Passwords / tokensDon’t put secrets in web storage (Security)

Install

bash
npm install @jayoncode/storage
bash
pnpm add @jayoncode/storage
bash
yarn add @jayoncode/storage

Example: prefs vs cache (policies)

Named policies are just reusable TTL presets — beginners can skip them and pass { ttl: … } on each set.

ts
import { createStorage, createLocalStorageAdapter } from "@jayoncode/storage";

const storage = createStorage({
  namespace: "app",
  adapter: createLocalStorageAdapter(),
  policies: {
    preferences: { ttl: { days: 365 } },
    cache: { ttl: { minutes: 15 } },
  },
});

storage.set("theme", "dark", { policy: "preferences" });
storage.set("feed", data, { policy: "cache" });

How the pieces fit

mermaid
flowchart LR
  App["Your app"] --> CS["createStorage"]
  CS --> Adapter["Adapter\n(memory / local / session)"]
  CS --> Env["Envelope\nvalue + savedAt + expiresAt?"]
  Adapter --> Browser["Browser storage"]
PiecePlain English
NamespaceFolder name for keys (app:theme)
AdapterWhere bytes live
EnvelopeYour value + metadata Storage stores for you
PolicyNamed default TTL for a kind of write
SubpathExtra tools you import only when needed

Problem → approach

Pain todayWhat Storage does
Hand-rolled JSON.parse + key prefixesOne createStorage per concern
Expiry logic copied into every readerTTL on write; auto-drop when you read
Old tabs break after a schema changeschemaVersion + migrate on get
Core API gets huge with GC / backup / watchThose live on subpaths

Cheatsheet

I want to…Call
Saveset(key, value)
Loadget(key) → value or null
See expiry / versionpeek(key)
Check without migratinghas(key)
Delete one keyremove(key)
Wipe this namespaceclear()
Sweep expired (advanced)cleanup from /maintenance

Documentation map

Beginner

GuideWhat you’ll learn
TutorialInstall → set/get/peek → first policy
Core conceptsEnvelope, TTL, adapters in plain language
RecipesCopy-paste prefs, cache, lists

Intermediate

GuideWhat you’ll learn
CoreAll options, migrate, adapters
ErrorsThrows vs soft null
Best practicesNaming, SSR, what not to store
FAQ · Browser support · SecurityEdge cases

Advanced

GuideWhat you’ll learn
MaintenanceExplicit GC report
SnapshotsExport / restore
ObservableIn-process watch / on
DiagnosticsDEV report / activity
TransactionsSame-tab rollback
Async / IndexedDBPromise API + IndexedDB adapter
Cross-tabNotify other tabs (no auto-merge)
QuotaSoft limits (approx bytes)
TransformsOpt-in compress / encrypt hooks
CompositionWire with BL / FI / OD in app code

Reference

An ecosystem of independent, headless TypeScript libraries engineered for modern web development. Every package includes interactive playgrounds and documentation that evolves alongside the code.