Getting started
Start storing JavaScript values in the browser with ultrastorage, from setup to React integration.
Store objects, dates, and other JavaScript values in the browser without writing serialization code. ultrastorage adds expiration, namespaces, and subscriptions to familiar storage methods, with an optional React adapter to keep components in sync.
Installation
One package includes the storage API and optional React adapter, so you can start with ordinary JavaScript or TypeScript and add React integration when you need it.
npm install ultrastorage
Create a shared instance
Use a shared storage instance so every part of your app reads and writes with the same namespace, backend, and serializer. Define it once in a module and import it wherever you need stored data.
import { createStorage } from 'ultrastorage';
// Create an app-wide singleton instance.
export const appStorage = createStorage({
// Optional, but highly recommended. The `theme` key will be stored as
// `acme:theme`, reducing the likelihood of collisions with third-party code.
prefix: 'acme',
});
import { appStorage } from './lib/app-storage';
appStorage.setItem('theme', 'dark');
appStorage.getItem('theme'); // 'dark'
appStorage.removeItem('theme');
getItem() returns deserialized values, and clear() only removes recognized entries within the
configured namespace. Use methods such as getItem('theme') instead of property access such as
storage.theme. Existing raw localStorage values need explicit migration before this instance
can read them; see Migration.
Store objects directly and add a TTL when data should only be used for a limited time:
appStorage.setItem('user', { name: 'Alice', age: 30 }, { ttl: 5_000 });
appStorage.getItem('user'); // { name: 'Alice', age: 30 }
// After five seconds:
appStorage.getItem('user'); // null
Use with React
For React apps, we recommend using the React adapter. It subscribes components to storage changes so your UI stays in sync, and provides a hook for reading, updating, and removing values.
In a React 18 or 19 application, import createStorageHook from ultrastorage/react and bind it to
your shared appStorage instance.
Create the bound hook outside components; no provider or separate adapter package is required.
import { createStorageHook } from 'ultrastorage/react';
import { appStorage } from './app-storage';
export const useAppStorage = createStorageHook(appStorage);
Call useAppStorage in a component to read a key and update it. Components reading the same key stay in sync when you write through the hook or appStorage.
'use client';
import { useAppStorage } from './lib/use-app-storage';
export function ThemePicker() {
const [theme, setTheme] = useAppStorage('theme', { defaultValue: 'light' });
return (
<button onClick={() => setTheme((previous) => (previous === 'light' ? 'dark' : 'light'))}>
Theme: {theme}
</button>
);
}
defaultValue is displayed when the key is missing and is never automatically written. Use
'use client' in frameworks with React Server Components.
See the React guide for schemas, expiration, and server rendering, or the React API reference for hook options.
Choose an entry point
The import path determines which APIs and dependencies your app includes. Start with ultrastorage
for default serialization, choose ultrastorage/core for your own serializer, and add
ultrastorage/react for reactive components.
| Import | Use it for |
|---|---|
ultrastorage |
Default devalue serialization, rich types, and all storage methods. |
ultrastorage/core |
Your own serializer, with no bundled devalue. |
ultrastorage/react |
useStorage and createStorageHook for React 18 and 19. |
Constructing an instance is safe on the server because default localStorage access is deferred until the first operation.
Ordinary reads and writes still require localStorage or another configured Storage object to be
available; use memory for server operations.