Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/christianbaroni/stores/llms.txt

Use this file to discover all available pages before exploring further.

This guide walks you through installing @storesjs/stores and composing a reactive store graph — a base store for settings, a query store for remote account data, and a derived store that combines them both — then consuming the result in a React component.
1

Install @storesjs/stores

Add @storesjs/stores to your project with your preferred package manager:
npm install @storesjs/stores
React ≥18 is an optional peer dependency for the React build. React Native ≥0.69 is required for the native build. See Installation for full peer dependency details.
2

Create a base store

A base store defines synchronous local state along with methods for updating it. Create settingsStore.ts to hold user preferences:
import { createBaseStore } from '@storesjs/stores';

type Settings = {
  currency: string;
  locale: string;
  setCurrency: (currency: string) => void;
};

export const settingsStore = createBaseStore<Settings>(set => ({
  currency: 'USD',
  locale: 'en-US',
  setCurrency: currency => set({ currency }),
}));
Read and update state outside React using the store object directly:
// Read current state
const { currency } = settingsStore.getState();

// Update state
settingsStore.getState().setCurrency('EUR');

// Subscribe to changes
const unsubscribe = settingsStore.subscribe(
  s => s.currency,
  currency => console.log('Currency changed:', currency)
);
3

Create a derived store

Derived stores compute values from other stores. The $ accessor tracks dependencies at runtime — whenever a tracked store changes, the derived store re-computes automatically:
import { createDerivedStore } from '@storesjs/stores';
import { settingsStore } from './settingsStore';

export const currencyFormatterStore = createDerivedStore($ => {
  const { currency, locale } = $(settingsStore);

  return new Intl.NumberFormat(locale, {
    currency,
    style: 'currency',
  });
});
Every property accessed through $(settingsStore)currency and locale — is tracked. If either changes, currencyFormatterStore produces a new Intl.NumberFormat instance.
Derived stores are read-only. They do not expose setState. If you need to combine remote data with local state, reach for a query store.
4

Create a query store

Query stores fetch, cache, and revalidate async data. Their params values can themselves be reactive — when a param changes, the store refetches:
import { createQueryStore, time } from '@storesjs/stores';
import { authStore } from './authStore';

type Account = {
  id: string;
  balance: number;
};

type Params = {
  userId: string;
};

export const accountStore = createQueryStore<Account, Params>({
  fetcher: fetchAccount,
  params: {
    userId: $ => $(authStore).userId,
  },
  staleTime: time.minutes(10),
});

async function fetchAccount({ userId }: Params): Promise<Account> {
  const res = await fetch(`/api/accounts/${userId}`);
  if (!res.ok) throw new Error('Failed to fetch account');
  return res.json();
}
The staleTime option controls how long cached data is considered fresh before a re-fetch is triggered. time.minutes(10) is a built-in helper that converts to milliseconds.Access the fetched data via getData():
// Outside React
const account = accountStore.getState().getData();

// Trigger a manual refetch
accountStore.getState().fetch();
5

Use stores as React hooks

In the React build, every store is a callable hook. Pass a selector to subscribe to only the slice of state you need — the component re-renders only when that value changes:
import { accountStore } from './accountStore';
import { currencyFormatterStore } from './currencyFormatterStore';
import { settingsStore } from './settingsStore';

function CurrencySelector() {
  const currency = settingsStore(s => s.currency);
  const setCurrency = settingsStore(s => s.setCurrency);

  return (
    <select value={currency} onChange={e => setCurrency(e.target.value)}>
      <option value="USD">USD</option>
      <option value="EUR">EUR</option>
      <option value="GBP">GBP</option>
    </select>
  );
}

Composed Example

Here is the full composed graph from the README — a derived store that formats an account balance using live settings, and a component that renders the result:
// currencyFormatterStore.ts
import { createDerivedStore } from '@storesjs/stores';
import { settingsStore } from './settingsStore';

export const currencyFormatterStore = createDerivedStore($ => {
  const { currency, locale } = $(settingsStore);
  return new Intl.NumberFormat(locale, {
    currency,
    style: 'currency',
  });
});
// accountBalanceStore.ts
import { createDerivedStore } from '@storesjs/stores';
import { accountStore } from './accountStore';
import { currencyFormatterStore } from './currencyFormatterStore';

export const accountBalanceStore = createDerivedStore($ => {
  const balance   = $(accountStore).getData()?.balance ?? 0;
  const formatter = $(currencyFormatterStore);
  return formatter.format(balance);
});
// AccountSummary.tsx
import { accountBalanceStore } from './accountBalanceStore';

function AccountSummary() {
  const balance = accountBalanceStore();
  return <Text>Balance: {balance}</Text>;
}
AccountSummary subscribes to accountBalanceStore, which in turn tracks accountStore and currencyFormatterStore. currencyFormatterStore tracks settingsStore. The entire chain reacts automatically — change the currency in settings and the displayed balance re-formats without any manual wiring.

Global Configuration

Before creating any stores, you can call configureStores() to set global defaults such as a custom storage backend, storage key prefix, or default query options:
import { configureStores, time } from '@storesjs/stores';

configureStores({
  storageKeyPrefix: 'myapp:',
  queryStoreDefaults: {
    staleTime: time.minutes(5),
  },
});
configureStores() must be called before any store is created. Calling it after the first store creation will throw in development. See the configuration guide for all available options.
Outside React, use .getState() to read and .subscribe(selector, listener) to react to changes. The callable hook form — store() — is only available in the React and React Native builds.

Build docs developers (and LLMs) love