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