Back to News & Insights
JavaScript September 24, 2026 · 6 min read

Browser Storage Doesn't Scale with Your Team. So I Built namespaced-storage

A few lines of localStorage usually look harmless. A feature remembers a filter. Authentication...

Browser Storage Doesn't Scale with Your Team. So I Built namespaced-storage

A feature remembers a filter. Authentication keeps a token. The basket survives a refresh.

Each decision makes sense in isolation. But in a large frontend codebase, owned by multiple teams, all of those features write into the same global namespace.

Working on a large-scale product at Snappfood, I have seen how quickly storage decisions spread across a codebase. Different teams move at different speeds. Features have different lifetimes. Engineers join, leave, and refactor. A key written today may still exist in a user's browser months later.

JavaScript gives us several ways to persist data, but the raw APIs provide very few boundaries: Keys are global to the origin Values are strings Ownership is invisible clear() affects everyone TypeScript cannot protect data after it crosses the storage boundary Nobody can easily answer what the application stores

That is why I built namespaced-storage, together with an ESLint plugin and a CLI.

Both changes look correct in their pull requests. Both may pass every test. In the browser, one silently overwrites the other.

This helps, but it is only a naming convention. Every engineer must remember it, spell it correctly, serialize values consistently, and avoid clearing data owned by another feature.

The basket feature can clear its state without removing authentication, UI preferences, or another team's data.

Storage is no longer owned by the application. Each piece of storage is owned by a feature.

There is no central registry that every team has to edit. Ownership remains local, while the tooling can still build a global view.

For data that needs runtime validation, the package includes a small schema API and also supports Standard Schema validators such as Zod, Valibot, and ArkType:

This protects both sides of the boundary: TypeScript catches incorrect writes during development Runtime validation catches invalid persisted data

It also round-trips regular JSON values plus Date, Map, Set, BigInt, RegExp, NaN, and infinity values.

Someone is fixing an urgent bug. Someone copies an old example. Someone writes directly to window.localStorage because it is faster than finding the abstraction.

The plugin includes four rules: no-direct-storage prevents raw localStorage and sessionStorage access require-namespace-literal keeps namespaces statically discoverable no-reserved-key protects internal metadata storage-file-convention keeps declarations in .storage.ts files in strict mode

Instead of relying on a code review comment, the feedback appears where the mistake is introduced:

The rule understands scope. A local variable called localStorage is not confused with the browser global, and adapter files can be explicitly allowed when raw access is intentional.

Good guardrails should be precise enough that teams do not need to disable them.

Want to discuss this further?

Book a free strategy call with our team to see how these insights apply to your specific business goals.

Book a consultation