Skip to content

Events

There are two types of events:

  • synced: Events that are synced across clients
  • clientOnly: Events that are only processed locally on the client (but still synced across client sessions e.g. across browser tabs/windows)

An event definition consists of a unique name of the event and a schema for the event arguments. It’s recommended to version event definitions to make it easier to evolve them over time.

Events will be synced across clients and materialized into state (i.e. SQLite tables) via materializers.

livestore/schema.ts
import { Events, Schema, sql } from '@livestore/livestore'
export const events = {
todoCreated: Events.synced({
name: 'v1.TodoCreated',
schema: Schema.Struct({ id: Schema.String, text: Schema.String }),
}),
todoCompleted: Events.synced({
name: 'v1.TodoCompleted',
schema: Schema.Struct({ id: Schema.String }),
}),
}
  • It’s strongly recommended to use past-tense event names (e.g. todoCreated/createdTodo instead of todoCreate/createTodo) to indicate something already occurred.
  • TODO: write down more best practices
  • TODO: mention AI linting (either manually or via a CI step)
    • core idea: feed list of best practices to AI and check if events adhere to them + get suggestions if not
  • It’s recommended to avoid DELETE events and instead use soft-deletes (e.g. add a deleted date/boolean column with a default value of null). This helps avoid some common concurrency issues.
  • Event definitions can’t be removed after they were added to your app.
  • Event schema definitions can be evolved as long as the changes are forward-compatible.
    • That means data encoded with the old schema can be decoded with the new schema.
    • In practice, this means …
      • for structs …
        • you can add new fields if they have default values or are optional
        • you can remove fields
// somewhere in your app
import { events } from './livestore/schema.js'
store.commit(
events.todoCreated({ id: '1', text: 'Buy milk' })
)

The history of all events that have been committed is stored forms the “eventlog”. It is persisted in the client as well as in the sync backend.

Example eventlog.db: