DEV Community

Cover image for I Built a Wrapper to Fix the Two Biggest Problems with LocalStorage
Kushal S T
Kushal S T

Posted on

I Built a Wrapper to Fix the Two Biggest Problems with LocalStorage

We all love localStorage. It is the easiest way to persist state in a web app. You don't need a database, you don't need a backend, and the API is dead simple: setItem and getItem.

But if you’ve built enough production apps, you know localStorage has two major flaws that eventually come back to bite you:

  1. It’s Immortal: Data stays there forever. Unless you manually write code to delete it, your user’s disk fills up with stale data from three years ago.

  2. It’s Exposed: Open the DevTools "Application" tab, and anyone can read (and edit) your application state in plain text.

I built a lightweight, zero-dependency TypeScript package to solve exactly these problems.

Meet @kushalst/local-storage-expiry

The Problem with "Forever" Storage

Imagine you cache a user’s profile to save an API call:

// Standard localStorage
localStorage.setItem('user', JSON.stringify({ name: 'Kushal', role: 'admin' }));
Enter fullscreen mode Exit fullscreen mode

If the user’s role changes to editor on the server, but your frontend logic prioritizes localStorage, the user might see the old admin dashboard for months—until they clear their cache manually.

To fix this, you usually have to write messy wrapper code to save a timestamp, check it on every read, and handle parsing errors. It’s boilerplate city.

The Solution: Built-in TTL (Time-To-Live)

With @kushalst/local-storage-expiry, expiration is a first-class citizen. You set a duration (in milliseconds), and the library handles the rest.

Installation

npm i @kushalst/local-storage-expiry
Enter fullscreen mode Exit fullscreen mode

Usage

The API is designed to feel exactly like the native one, just smarter.

import { set, get } from "@kushalst/local-storage-expiry";

// Cache this data for exactly 1 hour
set("userProfile", { id: 123, name: "Kushal" }, 60 * 60 * 1000);

// Later...
const profile = get("userProfile"); 
// Returns data if < 1 hour old.
// Returns null (and auto-deletes) if > 1 hour old.
Enter fullscreen mode Exit fullscreen mode

If the data is expired, the library automatically cleans it up for you immediately upon access. No more stale UI bugs.

Feature Highlight: Obfuscation

This is where standard wrappers usually stop, but I wanted something better.

By default, localStorage saves plain strings. If you walk away from your computer, anyone can open DevTools and see exactly what is stored.

This library automatically obfuscates your data using a lightweight XOR + Base64 algorithm.

  • Before (Standard): "user": "{\"id\":123,\"name\":\"Kushal\"}"
  • After (With this library): "lse_user": "eyJ2IjoxLCJlIjoxNzM1M... (gibberish) ..."

Is this military-grade encryption? No. (Never store passwords in localStorage!). But it prevents casual snooping and stops users from manually tampering with specific JSON fields to break your app state.

Feature Highlight: The Garbage Collector

"Lazy deletion" (deleting when you try to access the key) is great, but what about keys you never access again? They usually sit there, eating up your 5MB storage quota.

I included a flushExpired() utility that scans your storage and bulk-deletes dead keys.

import { flushExpired } from "@kushalst/local-storage-expiry";

// Run this on app startup (e.g., in useEffect or main.ts)
flushExpired();
Enter fullscreen mode Exit fullscreen mode

This ensures your app keeps a small footprint on the user's device, automatically removing junk from previous sessions.

Safety First: Namespacing

You might be worried: "Will flushExpired() delete data from other libraries or my other apps?"

No. The library automatically prefixes all keys with lse_

  • set('token') -> saves to lse_token
  • clear() -> only wipes keys starting with lse_

Your other localStorage data is completely safe.

Wrapping Up

If you are looking for a robust, type-safe way to handle client-side caching without pulling in massive dependencies, give this a try. It works in React, Vue, Angular, Svelte, and even vanilla JS.

📦 NPM: npmjs.com/package/@kushalst/local-storage-expiry

Happy coding!

Top comments (0)