https://livestore.dev
LiveStore BETA
DocsExamplesDevtools
Search Docs...
[?]K
Sponsor the project
Client A
try here
Release v0.3
Improved syncing + Node adapter
Build collaborative apps Build the next |
with synced SQLite
LiveStore is a next-generation state management framework based on
reactive SQLite and git-inspired syncing (via event-sourcing).
Get started Watch demo (3min)
"Events are the most accurate representation of state. LiveStore gets
it right."
David Khourshid
David Khourshid
Client B
syncs here
Works cross-platform
Chrome Expo Node.js Electron Tauri
Framework integrations
Vite React Solid Vue Svelte
Pluggable syncing provider
Cloudflare Electric S2
How it works
LiveStore is a fully-featured, client-centric data layer (replacing
libraries like Redux, MobX, etc.) with a reactive embedded SQLite
database powered by real-time sync (via event-sourcing).
On the clientSyncingServer clients
Client A
render
UI
commit
events
State
Events
reactive
query
DB
materialize
= Persisted in device storage
User Interface
LiveStore works with most UI frameworks (e.g. React, Solid, etc.)
allowing you to reactively query the database and trigger changes by
committing events.
*
*
*
User Interface
LiveStore works with most UI frameworks (e.g. React, Solid, etc.)
allowing you to reactively query the database and trigger changes by
committing events.
*
*
*
Commit Events
Events are defined as part of your LiveStore schema. Events are
committed by calling the commit method on the store.
schema.ts
import { Events, Schema } from '@livestore/livestore'
// Definition of a events
export const events = {
todoCreated: Events.synced({
name: 'v1.TodoCreated',
schema: Schema.Struct({ id: Schema.String, text: Schema.String, completed: Schema.Boolean.pipe(Schema.optional) }),
}),
todoCompleted: Events.synced({
name: 'v1.TodoCompleted',
schema: Schema.Struct({ id: Schema.String }),
}),
todoUncompleted: Events.synced({
name: 'v1.TodoUncompleted',
schema: Schema.Struct({ id: Schema.String }),
}),
todoDeleted: Events.synced({
name: 'v1.TodoDeleted',
schema: Schema.Struct({ id: Schema.String, deletedAt: Schema.Date }),
}),
}
todo.tsx
import { useStore } from '@livestore/react'
import { tables } from '../livestore/schema.js'
const Todo = ({ todo }: { todo: typeof tables.todos.Type }) => {
const { store } = useStore()
// Committed events update the database and are synced
const complete = () => store.commit(events.todoCompleted(todo.id))
return
{todo.text}
}
Events
When a event is committed, it's persisted in the eventlog, refreshes
the database (via materializers) and synced to other clients (if sync
is enabled).
Eventlog
eventNumber eventName Args ClientId SessionId
e0 Root {}
e1 v1.TodoCreated {"id":"djO3ELp02RxQgk4mRbJWF","text":"Learn GrETK0UW92hnRMIHGEgI3 T_xJ8w6PFX6wzK5if0xJ8
about LiveStore","completed":true}
e2 v1.TodoCreated {"id":"t3vUQjBZX4hvzrjnsgJ-V","text":"Try GrETK0UW92hnRMIHGEgI3 T_xJ8w6PFX6wzK5if0xJ8
LiveStore devtools"}
e3 v1.TodoCreated {"id":"MRPD4ICIBP58tpSZ89CB7","text":"Build GrETK0UW92hnRMIHGEgI3 T_xJ8w6PFX6wzK5if0xJ8
a LiveStore app"}
Materialize
Materializers are callback functions that map events to state changes
via SQL statements. LiveStore comes with a built-in query builder.
schema.ts
import { State } from '@livestore/livestore'
// Materializers are used to map events to state
const materializers = State.SQLite.materializers(events, {
'v1.TodoCreated': ({ id, text, completed }) => tables.todos.insert({ id, text, completed }),
'v1.TodoCompleted': ({ id }) => tables.todos.update({ completed: true }).where({ id }),
'v1.TodoUncompleted': ({ id }) => tables.todos.update({ completed: false }).where({ id }),
'v1.TodoDeleted': ({ id, deletedAt }) => tables.todos.update({ deletedAt }).where({ id }),
})
Event
{
eventNumber: 'e1',
eventName: 'v1.TodoCreated',
data: {
id: 'djO3ELp02RxQgk4mRbJWF',
text: 'Learn about LiveStore',
completed: true
}
}
SQL
INSERT INTO todos (id, text, completed)
VALUES (
'djO3ELp02RxQgk4mRbJWF',
'Learn about LiveStore',
1
)
Database
LiveStore comes with an embedded reactive SQLite database which is
automatically kept up to date via materializers and persisted to
device storage.
schema.ts
import { Schema, State } from '@livestore/livestore'
// You can model your state as SQLite tables which you can reactively query
export const tables = {
todos: State.SQLite.table({
name: 'todos',
columns: {
id: State.SQLite.text({ primaryKey: true }),
text: State.SQLite.text({ default: '' }),
completed: State.SQLite.boolean({ default: false }),
deletedAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),
},
}),
}
Database
id text completed deletedAt
djO3ELp02RxQgk4mRbJWF Learn about LiveStore true null
t3vUQjBZX4hvzrjnsgJ-V Try LiveStore devtools false null
MRPD4ICIBP58tpSZ89CB7 Build a LiveStore app false null
Reactive Query
LiveStore allows you to reactively query the database (via
querybuilder, raw SQL, etc.). Query results are instant and don't
require a loading state.
app.tsx
import { useQuery } from '@livestore/react'
import { queryDb } from '@livestore/livestore'
import { tables } from '../livestore/schema.js'
const todos$ = queryDb(
(get) => tables.todos.where({ deletedAt: null })
)
export const Todos = () => {
const todos = useQuery(todos$)
// Reactively updates when the database changes. No loading state needed.
return (
{todos.map((todo) => (
))}
)
}
State (Query results)
Query results are returned as plain immutable JavaScript objects/
arrays.
// Log to console to see the state
console.log(todos)
// [
// {
// id: 'djO3ELp02RxQgk4mRbJWF',
// text: 'Learn about LiveStore',
// completed: true
// },
// {
// id: 't3vUQjBZX4hvzrjnsgJ-V',
// text: 'Try LiveStore devtools',
// completed: false
// },
// {
// id: 'MRPD4ICIBP58tpSZ89CB7',
// text: 'Build a LiveStore app',
// completed: false
// },
// ]
Render
Whenever the state changes, the component is re-rendered.
app.tsx
import { useQuery, useStore } from '@livestore/react'
import { tables } from '../livestore/schema.js'
const visibleTodos$ = queryDb(..) // see reactive query
export const Todos = () => {
const todos = useQuery(visibleTodos$)
return (
{todos.map((todo) => (
))}
)
}
const Todo = ({ todo }: { todo: typeof tables.todos.Type }) => {
const { store } = useStore()
const complete = () => store.commit(events.todoCompleted(todo.id))
return {todo.text}
}
Let's look at a real example
The following is a simple TodoMVC app built with LiveStore showing
how to model your events, state and reactively query the database.
See more examples on GitHub
Try out the LiveStore Devtools
Learn more
Demos speak louder than words
LiveStore is designed for demanding & high-performance apps. Let's
see it in action.
Overtone
Overtone
Next-gen music app
Linearlite Web
Linearlite Web
Linear clone (Web)
Linearlite Mobile
Linearlite Mobile
Linear clone (Expo)
Outlyne
Outlyne
AI website builder
Fun fact: LiveStore was originally developed as a part of Overtone
and later factored out.
Designed and optimized for demanding applications
LiveStore is based on years of research and was developed as the data
foundation for uncompromising apps like Overtone.
GeneralReact-specificSync-specificComparison
Reactive & persisted SQLite
Reactive & persisted SQLite
LiveStore is based on SQLite enabling instant reactive queries while
efficiently persisting data in the background.
Learn more
Real-time sync engine
Real-time sync engine
LiveStore includes a built-in sync engine based on event sourcing
(similar to Git) allowing for complex syncing scenarios.
Learn more
Premium DX & devtools
Premium DX & devtools
For best-in-class developer experience, LiveStore offers first-class
devtools similar to Chrome DevTools but for your data.
Learn more
High performance
LiveStore was designed for high-performance applications enabling
developers to build complex apps running at 120 FPS.
Powerful type-safe schema
LiveStore offers a powerful type-safe schema API allowing for
ergonomic data modeling and evolution without database migrations.
Local-first
LiveStore allows you to build local-first/offline-first apps by
taking care of the hardest part: data management.
What LiveStore does vs. what not
LiveStore was designed to be a principled and flexible data layer.
It's design decisions might make it unsuitable for some use cases.
Learn more about when to use LiveStore.
What LiveStore does
* Provide a powerful data foundation for your app.
* Reactive query layer with full SQLite support.
* Adapters for most platforms (web, mobile, server/edge, desktop).
* Flexible data modeling and schema management.
* Support true offline-first workflows.
* Custom merge conflict resolution.
* Sync with a supported provider or roll your own.
* Helps avoid data vendor lock-in.
What LiveStore doesn't do
* Not a batteries-included framework (no auth, file upload, etc).
* Not a good fit for some use cases.
* Doesn't sync with your existing database.
* Doesn't provide a hosted service.
* Doesn't scale for unbounded amounts of data.
* Doesn't support peer-to-peer/decentralized syncing.
* Sell your data.
What others are saying
David Khourshid
David Khourshid
Creator of XState
Events are the most accurate representation of state. Everything else
is a lossy abstraction. LiveStore gets it right [?][?]
Sunil Pai
Sunil Pai
Engineer @Cloudflare
I'm so very excited for @schickling's livestore to drop, really
deeply considered and principled way to build great user interfaces.
Beto Moedano
Beto Moedano
Developer Advocate @Expo
@livestoredev + @expo + @CloudflareDev = Local-First app with
real-time sync, offline persistence, and smooth performance.
Jacob Clausen
Jacob Clausen
App Developer
There's so much to be excited about with @livestoredev. But what
really gets me is the extra mile they've gone with the dev tools.
Top-tier stuff that adds serious value. Plus, it's an @expo dev
plugin, making it seamless and well integrated. A dream combo for
offline-first!
Peter Pistorius
Peter Pistorius
Co-creator RedwoodSDK
What are you syncing about? Just got a preview of @livestoredev v2 by
@schickling: it's next-level.
Johannes Schickling
Johannes Schickling
Creator of LiveStore
I think LiveStore is pretty cool but I'm biased. However, you should
give it a try.
Show more
Additional resources
Check out the following resources to learn more about LiveStore.
Conference talk
You can learn more about LiveStore in some of our past conference
talks.
Read more
Office hours
Watch some of the past LiveStore office hours recordings and join the
next one.
Read more
Riffle essay
In the Riffle essay (+ PhD thesis by Geoffrey Litt), we explored the
idea of reactive SQLite as a modern state management system.
Read more
The story behind LiveStore
LiveStore was designed and developed as foundation for Overtone, a
next-gen music app. To achieve the high-performance requirements of
the app, we needed a state management framework that is able to
handle the complex data scenarios of the app which started the Riffle
research project and later became LiveStore.
[johannes-s]
Creator of
Overtone Prisma
Get started
Give LiveStore a try. Start with an existing example or add it to
your own project.
Get started Watch demo (3min)
Sponsor the project
Become a sponsor and get access to...
* LiveStore devtools
* Discord channel
* Community
Sponsor the project
LiveStore BETA
Made with care by Overengineering Studio & contributors
(c) 2025
Resources
* Docs
* Examples
* Devtools
Community
Github Discord Bluesky Twitter