> [Agent navigation index](/llms.txt)

# Use typed browser storage helpers

Read, write, remove, validate, and test JSON-serialized browser values outside component render lifecycles.

Storage is persisted client state. For in-memory coordination across Preact island roots on one page,
use [stores](/docs/stores) instead.

## Use raw helpers outside components

```ts
import { getLocalStorageItem, removeLocalStorageItem, setLocalStorageItem } from "brix/storage";
import { profileKey } from "./storage-keys.ts";

setLocalStorageItem(profileKey, { displayName: "Ada", visits: 3 });
const profile = getLocalStorageItem(profileKey);
removeLocalStorageItem(profileKey);

```

Session equivalents are `getSessionStorageItem`, `setSessionStorageItem`, and
`removeSessionStorageItem`. Generic `getStorageItem`, `setStorageItem`, and `removeStorageItem` take a
supplied `Storage` first, and therefore work with compatible in-memory or platform implementations.

All values are JSON encoded, including strings. Do not read the underlying item and assume its stored
text equals the logical string value.

## Validation and errors

Reads are lenient because browser data may be malformed or from an older schema:

- Valid JSON is parsed through Zod and returns schema output.
- Malformed JSON or schema-invalid data returns `null`.
- Zod transformations and ordinary object-key stripping apply to both reads and writes.

Raw writes are strict. They parse before writing and throw for schema-invalid input, which exposes a
developer error. Hook writes are UI-safe: invalid input leaves both storage and rendered state
unchanged. If serialization or persistence fails, a hook retains its previous value instead of
claiming an unpersisted update succeeded.

Do not use storage for secrets, authorization decisions, or trustworthy server state. Browser users
can inspect and modify it. Validate again at every API or server boundary.

## SSR and unavailable storage

The local and session convenience APIs do not access `window` during SSR:

- Reads return `null`.
- Writes and removals are no-ops.
- Hooks use lazy initialization and initially render with `null` on the server.

Browser privacy settings, sandboxing, and quota failures degrade similarly: reads return `null`, and
writes or removals do not break rendering. Account for server-to-client changes when persisted data
affects visible markup; keep the server fallback deterministic to avoid hydration surprises. See
[islands](/docs/islands) for serialization and hydration boundaries.

## Test behavior

Use browser component tests for hooks, events, and cross-tab behavior. For raw generic helpers, inject
a small test `Storage` implementation and test valid values, malformed JSON, schema migrations,
removal, and write failures. Reset keys between tests to prevent state leakage.

```sh
brix test --project browser
brix test --project node
brix check

```

See [testing](/docs/testing) for selecting browser and node projects. Persisted values are independent
of Brix's server-side [data caching](/docs/caching).
