Skip to content
ultrastorageultrastorage
Esc
↑↓navigate↵open⌘Jpreview
On this page

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.

Was this page helpful?