Skip to content

Store

Defined in: packages/@livestore/livestore/src/store/store.ts:129

Central interface to a LiveStore database providing reactive queries, event commits, and sync.

A Store instance wraps a local SQLite database that is kept in sync with other clients via an event log. Instead of mutating state directly, you commit events that get materialized into database rows. Queries automatically re-run when their underlying tables change.

Use createStore (Effect-based) or createStorePromise to obtain a Store instance. In React applications, use the <LiveStoreProvider> component which manages the Store lifecycle and exposes it via React context.

Use Store.query for one-shot reads or Store.subscribe for reactive subscriptions. Both accept query builders (e.g. tables.todo.where({ complete: true })) or custom LiveQueryDefs.

Use Store.commit to persist events. Events are immediately materialized locally and asynchronously synced to other clients. Multiple events can be committed atomically.

The Store must be shut down when no longer needed via Store.shutdown or Store.shutdownPromise. Framework integrations (React, Effect) handle this automatically.

// Query data
const todos = store.query(tables.todo.where({ complete: false }))
// Subscribe to changes
const unsubscribe = store.subscribe(tables.todo.all(), (todos) => {
console.log('Todos updated:', todos)
})
// Commit an event
store.commit(events.todoCreated({ id: nanoid(), text: 'Buy milk' }))
  • Class

TSchema extends LiveStoreSchema = Any

The LiveStore schema defining tables and events

TContext = { }

Optional user-defined context attached to the Store (e.g. for dependency injection)

new Store<TSchema, TContext>(__namedParameters): Store<TSchema, TContext>

Defined in: packages/@livestore/livestore/src/store/store.ts:185

StoreOptions<TSchema, TContext>

Store<TSchema, TContext>

Inspectable.Class.constructor

readonly [StoreInternalsSymbol]: StoreInternals

Defined in: packages/@livestore/livestore/src/store/store.ts:182

Store internals. Not part of the public API — shapes and semantics may change without notice.


commit: {<TCommitArg>(…list): void; (txn): void; <TCommitArg>(options, …list): void; (options, txn): void; }

Defined in: packages/@livestore/livestore/src/store/store.ts:764

Commit a list of events to the store which will immediately update the local database and sync the events across other clients (similar to a git commit).

<TCommitArg>(…list): void

TCommitArg extends readonly ForSchema<TSchema>[]

TCommitArg

void

(txn): void

<TCommitArg>(…list) => void

void

<TCommitArg>(options, …list): void

TCommitArg extends readonly ForSchema<TSchema>[]

StoreCommitOptions

TCommitArg

void

(options, txn): void

StoreCommitOptions

<TCommitArg>(…list) => void

void

store.commit(events.todoCreated({ id: nanoid(), text: 'Make coffee' }))

You can call commit with multiple events to apply them in a single database transaction.

const todoId = nanoid()
store.commit(
events.todoCreated({ id: todoId, text: 'Make coffee' }),
events.todoCompleted({ id: todoId }))

For more advanced transaction scenarios, you can pass a synchronous function to commit which will receive a callback to which you can pass multiple events to be committed in the same database transaction. Under the hood this will simply collect all events and apply them in a single database transaction.

store.commit((commit) => {
const todoId = nanoid()
if (Math.random() > 0.5) {
commit(events.todoCreated({ id: todoId, text: 'Make coffee' }))
} else {
commit(events.todoCompleted({ id: todoId }))
}
})

When committing a large batch of events, you can also skip the database refresh to improve performance and call store.manualRefresh() after all events have been committed.

const todos = [
{ id: nanoid(), text: 'Make coffee' },
{ id: nanoid(), text: 'Buy groceries' },
// ... 1000 more todos
]
for (const todo of todos) {
store.commit({ skipRefresh: true }, events.todoCreated({ id: todo.id, text: todo.text }))
}
store.manualRefresh()

readonly context: TContext

Defined in: packages/@livestore/livestore/src/store/store.ts:137

User-defined context attached to this Store (e.g. for dependency injection).


readonly networkStatus: Subscribable<{ devtools: { latchClosed: boolean; }; isConnected: boolean; timestampMs: number; }, never, never>

Defined in: packages/@livestore/livestore/src/store/store.ts:159

Reactive connectivity updates emitted by the backing sync backend.

import { Effect, Stream } from 'effect'
const status = await store.networkStatus.pipe(Effect.runPromise)
await store.networkStatus.changes.pipe(
Stream.tap((next) => console.log('network status update', next)),
Stream.runDrain,
Effect.scoped,
Effect.runPromise,
)

readonly params: object

Defined in: packages/@livestore/livestore/src/store/store.ts:140

Options provided to the Store constructor.

optional eventQueryBatchSize: number

leaderPushBatchSize: number

optional simulation: object

clientSessionSyncProcessor: object

simulation.clientSessionSyncProcessor.pull
Section titled “simulation.clientSessionSyncProcessor.pull”

readonly pull: object

simulation.clientSessionSyncProcessor.pull.1_before_leader_push_fiber_interrupt
Section titled “simulation.clientSessionSyncProcessor.pull.1_before_leader_push_fiber_interrupt”

readonly 1_before_leader_push_fiber_interrupt: number

simulation.clientSessionSyncProcessor.pull.2_before_leader_push_queue_clear
Section titled “simulation.clientSessionSyncProcessor.pull.2_before_leader_push_queue_clear”

readonly 2_before_leader_push_queue_clear: number

simulation.clientSessionSyncProcessor.pull.3_before_rebase_rollback
Section titled “simulation.clientSessionSyncProcessor.pull.3_before_rebase_rollback”

readonly 3_before_rebase_rollback: number

simulation.clientSessionSyncProcessor.pull.4_before_leader_push_queue_offer
Section titled “simulation.clientSessionSyncProcessor.pull.4_before_leader_push_queue_offer”

readonly 4_before_leader_push_queue_offer: number

simulation.clientSessionSyncProcessor.pull.5_before_leader_push_fiber_run
Section titled “simulation.clientSessionSyncProcessor.pull.5_before_leader_push_fiber_run”

readonly 5_before_leader_push_fiber_run: number


readonly schema: LiveStoreSchema

Defined in: packages/@livestore/livestore/src/store/store.ts:134

The LiveStore schema defining tables, events, and materializers.


readonly storageMode: "persisted" | "in-memory"

Defined in: packages/@livestore/livestore/src/store/store.ts:177

Indicates how data is being stored.

  • persisted: Data is persisted to disk (e.g., via OPFS on web, SQLite file on native)
  • in-memory: Data is only stored in memory and will be lost on page refresh

The store operates in in-memory mode when persistent storage is unavailable, such as in Safari/Firefox private browsing mode where OPFS is restricted.

if (store.storageMode === 'in-memory') {
showWarning('Data will not be persisted in private browsing mode')
}

readonly storeId: string

Defined in: packages/@livestore/livestore/src/store/store.ts:131

Unique identifier for this Store instance, stable for its lifetime.


subscribe: SubscribeFn

Defined in: packages/@livestore/livestore/src/store/store.ts:467

Subscribe to the results of a query.

  • When providing an onUpdate callback it returns an Unsubscribe function.
  • Without a callback it returns an AsyncIterable that yields query results.
const unsubscribe = store.subscribe(query$, (result) => console.log(result))
for await (const result of store.subscribe(query$)) {
console.log(result)
}

get clientId(): string

Defined in: packages/@livestore/livestore/src/store/store.ts:436

Stable client identifier for the process/device using this Store.

  • Shared across Store instances created by the same client
  • Useful for diagnostics and multi-client correlation

string


get sessionId(): string

Defined in: packages/@livestore/livestore/src/store/store.ts:426

Current session identifier for this Store instance.

  • Stable for the lifetime of the Store
  • Useful for correlating events or scoping per-session data

string

events(options?): AsyncIterable<ForSchema<TSchema>>

Defined in: packages/@livestore/livestore/src/store/store.ts:903

Returns an async iterable of events from the eventlog. Currently only events confirmed by the sync backend is supported.

Defaults to tracking upstreamHead as it advances. If an until event is supplied the stream finalizes upon reaching it.

To start streaming from a specific point in the eventlog you can provide a since event.

Allows filtering by:

  • filter: event types
  • clientIds: client identifiers
  • sessionIds: session identifiers

The batchSize option controls the maximum amount of events that are fetched from the eventlog in each query. Defaults to 100 and has a max allowed value of 1000.

TODO:

  • Support streaming unconfirmed events
  • Leader level
  • Session level
  • Support streaming client-only events

StoreEventsOptions<TSchema>

AsyncIterable<ForSchema<TSchema>>

// Stream todoCompleted events from the start
for await (const event of store.events(filter: ['todoCompleted'])) {
console.log(event)
}
// Start streaming from a specific event
for await (const event of store.events({ since: EventSequenceNumber.Client.fromString('e3') })) {
console.log(event)
}

eventsStream(options?): Stream<ForSchema<TSchema>, UnknownError>

Defined in: packages/@livestore/livestore/src/store/store.ts:919

Returns an Effect Stream of events from the eventlog. See store.events for details on options and behaviour.

StoreEventsOptions<TSchema>

Stream<ForSchema<TSchema>, UnknownError>


manualRefresh(options?): void

Defined in: packages/@livestore/livestore/src/store/store.ts:945

This can be used in combination with skipRefresh when committing events. We might need a better solution for this. Let’s see.

string

void


query<TResult>(query, options?): TResult

Defined in: packages/@livestore/livestore/src/store/store.ts:606

Synchronously queries the database without creating a LiveQuery. This is useful for queries that don’t need to be reactive.

Example: Query builder

const completedTodos = store.query(tables.todo.where({ complete: true }))

Example: Raw SQL query

const completedTodos = store.query({ query: 'SELECT * FROM todo WHERE complete = 1', bindValues: {} })

TResult

Queryable<TResult> | { bindValues: Bindable; query: string; schema?: Schema<TResult, TResult, never>; }

RefreshReason

Context

TResult


setSignal<T>(signalDef, value): void

Defined in: packages/@livestore/livestore/src/store/store.ts:695

Set the value of a signal

T

SignalDef<T>

T | (prev) => T

void

const count$ = signal(0, { label: 'count$' })
store.setSignal(count$, 2)
const count$ = signal(0, { label: 'count$' })
store.setSignal(count$, (prev) => prev + 1)

shutdown(cause?): Effect<void>

Defined in: packages/@livestore/livestore/src/store/store.ts:978

Shuts down the store and closes the client session.

This is called automatically when the store was created using the React or Effect API.

Cause<UnknownError | MaterializeError>

Effect<void>


shutdownPromise(cause?): Promise<void>

Defined in: packages/@livestore/livestore/src/store/store.ts:966

Shuts down the store and closes the client session.

This is called automatically when the store was created using the React or Effect API.

UnknownError

Promise<void>


subscribeStream<TResult>(query, options?): Stream<TResult>

Defined in: packages/@livestore/livestore/src/store/store.ts:572

TResult

Queryable<TResult>

SubscribeOptions<TResult>

Stream<TResult>


toJSON(): object

Defined in: packages/@livestore/livestore/src/store/store.ts:1058

object

_tag: string = 'livestore.Store'

reactivityGraph: ReactiveGraphSnapshot

Inspectable.Class.toJSON