Releases: livestorejs/livestore
Release list
v0.4.0
Installing v0.4.0: Make sure all LiveStore packages use the same version:
pnpm add @livestore/livestore @livestore/adapter-web @livestore/wa-sqlite @livestore/react # Or for Cloudflare pnpm add @livestore/livestore @livestore/adapter-cloudflare @livestore/sync-cf
Highlights
- New Cloudflare adapter: Added the Workers/Durable Object adapter and rewrote the sync provider so LiveStore ships WebSocket, HTTP, and Durable Object RPC transports as first-party Cloudflare options (#528, #591).
- S2 sync backend: Map LiveStore's event log onto S2's durable stream store via
@livestore/sync-s2, unlocking scalable basins/streams, SSE live tails, and transport-safe batching for large sync workloads (#292, #709). - Schema-first tables: LiveStore now accepts Effect schema definitions as SQLite table definitions, removing duplicate column configuration in applications (#544).
- Cloudflare sync provider storage: Default storage is now Durable Object (DO) SQLite, with an explicit option to use D1 via a named binding. Examples and docs updated to the DO‑by‑default posture (see issue #266, #693).
- MCP support: LiveStore now ships a CLI with a first-class MCP server so automation flows can connect to instances, query data, and commit events using the bundled tools (#705).
- React multi-store API: The multi-store API is now the primary React integration, replacing
<LiveStoreProvider>with<StoreRegistryProvider>anduseStore()with store options. The new API supports multiple stores, preloading, and caching out of the box. See the React integration docs (#841).
Breaking Changes
-
store.shutdownAPI: The shutdown method now returns an Effect instead of a Promise. Useyield* store.shutdown()inside Effects orawait store.shutdownPromise()when a Promise is needed.// Before await store.shutdown() // After (Effect API) yield * store.shutdown() // Or use the Promise helper await store.shutdownPromise()
-
store.subscribecallback signature: The subscription callback is now passed as the second argument, with subscription options moved to an optional third argument object. Replace usages likestore.subscribe(query$, { onUpdate })withstore.subscribe(query$, onUpdate, options). -
QueryBuilder.first()behaviour:table.query.first()now returnsundefinedwhen no rows match. To keep the old behaviour, pass{ behaviour: "error" }, or supply a fallback.// Before: threw an error when no rows matched const user = table.query.first() // throws // After: returns undefined when no rows match const user = table.query.first() // returns undefined // To preserve old behaviour const strictUser = table.query.first({ behaviour: 'error' }) // Or provide a fallback value const fallbackUser = table.query.first({ behaviour: 'fallback', fallback: () => ({ id: 'default', name: 'Guest' }), })
-
Raw SQL event availability: The
livestore.RawSqlevent is no longer added automatically. Define it explicitly when needed (#469):import { Events, Schema } from '@livestore/livestore' const rawSqlEvent = Events.clientOnly({ name: 'livestore.RawSql', schema: Schema.Struct({ sql: Schema.String, bindValues: Schema.optional(Schema.Record({ key: Schema.String, value: Schema.Any })), writeTables: Schema.optional(Schema.ReadonlySet(Schema.String)), }), })
-
wa-sqlite version alignment:
@livestore/wa-sqlitenow follows LiveStore's versioning scheme to keep adapters on matching releases.# Before: wa-sqlite had independent versioning pnpm add wa-sqlite@1.0.5 # After: wa-sqlite follows LiveStore versioning pnpm add @livestore/wa-sqlite@dev
This change affects projects that directly depend on wa-sqlite. Most users rely on it indirectly through LiveStore adapters and don't need to change anything.
-
Cloudflare sync provider storage selection: Removed implicit D1 auto‑selection and env‑based fallbacks. D1 must be selected explicitly via
storage: { _tag: 'd1', binding: 'DB' }on the sync Durable Object. The default is DO SQLite (see issue #266, #693).Before (implicit D1 when env.DB was present):
export class SyncBackendDO extends makeDurableObject({ // storage engine auto‑selected based on env }) {}
After (explicit binding for D1):
// wrangler.toml // [[d1_databases]] // binding = "DB" // database_name = "your-db" // database_id = "..." // code export class SyncBackendDO extends makeDurableObject({ storage: { _tag: 'd1', binding: 'DB' }, }) {}
To use the default DO SQLite, omit the
storageoption or pass{ _tag: 'do-sqlite' }. -
Restructured
LiveStoreEventandEventSequenceNumberAPIs: Types are now organized into symmetricGlobal,Client, andInputnamespaces that clarify the distinction between sync backend format, client format, and events without sequence numbers (#855):Old Name New Name LiveStoreEvent.AnyEncodedGlobalLiveStoreEvent.Global.EncodedLiveStoreEvent.AnyEncodedLiveStoreEvent.Client.EncodedLiveStoreEvent.AnyDecodedLiveStoreEvent.Client.DecodedLiveStoreEvent.PartialAnyEncodedLiveStoreEvent.Input.EncodedLiveStoreEvent.PartialAnyDecodedLiveStoreEvent.Input.DecodedLiveStoreEvent.EncodedWithMetaLiveStoreEvent.Client.EncodedWithMetaEventSequenceNumber.GlobalEventSequenceNumberEventSequenceNumber.GlobalEventSequenceNumber.globalEventSequenceNumberEventSequenceNumber.Global.makeEventSequenceNumber.localEventSequenceNumberEventSequenceNumber.Client.makeEventSequenceNumber.clientDefaultEventSequenceNumber.Client.DEFAULTEventSequenceNumber.rebaseGenerationDefaultEventSequenceNumber.REBASE_GENERATION_DEFAULTLiveStoreEvent.EventDefPartialSchemaLiveStoreEvent.EventDefInputSchemaLiveStoreEvent.makeEventDefPartialSchemaLiveStoreEvent.makeEventDefInputSchema// Before import { LiveStoreEvent, EventSequenceNumber } from '@livestore/livestore' const event: LiveStoreEvent.AnyEncoded = { ... } const globalSeq: EventSequenceNumber.GlobalEventSequenceNumber = 1 // After import { LiveStoreEvent, EventSequenceNumber } from '@livestore/livestore' const event: LiveStoreEvent.Client.Encoded = { ... } const globalSeq: EventSequenceNumber.Global = 1
-
Error class rename:
UnexpectedErrorhas been renamed toUnknownErrorfor better semantic clarity and consistency with Effect ecosystem naming conventions. The previous name conflicted with Effect's terminology where "unexpected errors" refer to defects, while this error type represents errors of unknown type from external libraries or infrastructure failures (See PR #823).Update all references:
- Class name:
UnexpectedError→UnknownError - Error tag:
'LiveStore.UnexpectedError'→'UnknownError' - Static methods:
mapToUnexpectedError*→mapToUnknownError* - Related type:
MergeResultUnexpectedError→MergeResultUnknownError
// Before import { UnexpectedError } from '@livestore/common' effect.pipe(UnexpectedError.mapToUnexpectedError) // After import { UnknownError } from '@livestore/common' effect.pipe(UnknownError.mapToUnknownError)
- Class name:
-
React integration API: The multi-store API is now the primary React integration, replacing
<LiveStoreProvider>and the olduseStore(). The new API usesStoreRegistry,<StoreRegistryProvider>, anduseStore()with store options. See the React integration docs for full details (#841).Before After <LiveStoreProvider schema={...} adapter={...}><StoreRegistryProvider storeRegistry={...}>+storeOptions({ ... })const { store } = useStore()const store = useStore({ ... })useQuery(query$)store.useQuery(query$)// Before import { LiveStoreProvider, useStore, useQuery } from '@livestore/react' const App = () => ( <LiveStoreProvider schema={schema} adapter={adapter} batchUpdates={batchUpdates}> <MyComponent /> </LiveStoreProvider> ) const MyComponent = () => { const { store } = useStore() const todos = useQuery(visibleTodos$) // ... } // After import { StoreRegistry } from '@livestore/livestore' import { StoreRegistryProvider, useStore } from '@livestore/react' const useAppStore = () => useStore({ storeId: 'app-root', schema, adapter, batchUpdates, }) const App = () => { const [storeRegistry] = useState(() => new StoreRegistry()) return ( <Suspense fallback={<div>Loading...</div>}> <StoreRegistryProvider storeRegis...
v0.4.0-dev.27
Release 0.4.0-dev.27
v0.4.0-dev.26
Release 0.4.0-dev.26
v0.4.0-dev.25
Release 0.4.0-dev.25
v0.4.0-dev.24
Release 0.4.0-dev.24
"v0.4.0-dev.23"
Release 0.4.0-dev.23.
Posted on behalf of @schickling
| field | value |
|---|---|
agent_name |
🌱 co1-alder |
agent_session_id |
6c624c62-4e38-435e-b267-475ef99d9340 |
agent_tool |
Codex CLI |
agent_tool_version |
codex-cli 0.124.0 |
agent_runtime |
Codex CLI codex-cli 0.124.0 |
agent_model |
unknown |
worktree |
megarepo-all/schickling/2026-04-26-livestore-release |
machine |
dev3 |
tooling_profile |
dotfiles@19cf6f4 |
"v0.4.0-dev.22"
"Release 0.4.0-dev.22 including Chrome Extension"
"v0.4.0-dev.21"
"Release 0.4.0-dev.21 including Chrome Extension"
"v0.4.0-dev.20"
"Release 0.4.0-dev.20 including Chrome Extension"
"v0.4.0-dev.19"
"Release 0.4.0-dev.19 including Chrome Extension"