Skip to content

Solid integration

See examples for a complete example.

import {
const makePersistedAdapter: (options: WebAdapterOptions) => Adapter

Creates a web adapter with persistent storage (currently only supports OPFS). Requires both a web worker and a shared worker.

On browsers without SharedWorker support (e.g. Android Chrome), this adapter automatically falls back to single-tab mode. In single-tab mode:

  • Each tab runs independently with its own leader worker
  • Multi-tab synchronization is not available
  • Devtools are not supported

@seehttps://github.com/livestorejs/livestore/issues/321 - SharedWorker tracking issue

@seehttps://issues.chromium.org/issues/40290702 - Chromium SharedWorker bug

@example

import { makePersistedAdapter } from '@livestore/adapter-web'
import LiveStoreWorker from './livestore.worker.ts?worker'
import LiveStoreSharedWorker from '@livestore/adapter-web/shared-worker?sharedworker'
const adapter = makePersistedAdapter({
worker: LiveStoreWorker,
sharedWorker: LiveStoreSharedWorker,
storage: { type: 'opfs' },
})

makePersistedAdapter
} from '@livestore/adapter-web'
import
const LiveStoreSharedWorker: new (options?: {
name?: string;
}) => SharedWorker
LiveStoreSharedWorker
from '@livestore/adapter-web/shared-worker?sharedworker'
import {
const useStore: <TSchema extends LiveStoreSchema, TContext = {}, TSyncPayloadSchema extends Schema<any> = Schema<JsonValue>>(options: AccessorMaybe<RegistryStoreOptions<TSchema, TContext, TSyncPayloadSchema>>) => Resource<Store<TSchema, TContext>> & SolidApi

Returns a store resource that suspends until the store is loaded. The store is cached by its storeId in the StoreRegistry.

@example

import { Suspense } from 'solid-js'
function Issue(props: { issueId: string }) {
const store = useStore(issueStoreOptions(props.issueId))
const issues = store()?.useQuery(queryDb(tables.issue.select()))
return (
<Show when={store()}>
{(s) => <IssueView store={s()} />}
</Show>
)
}
// With Suspense boundary
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Issue issueId="abc123" />
</Suspense>
)
}

@returnsA Resource that resolves to the loaded store instance augmented with Solid hooks

useStore
} from '@livestore/solid'
import
const LiveStoreWorker: new (options?: {
name?: string;
}) => Worker
LiveStoreWorker
from './livestore.worker.ts?worker'
import {
import schema
schema
} from './schema.ts'
const
const adapter: Adapter
adapter
=
function makePersistedAdapter(options: WebAdapterOptions): Adapter

Creates a web adapter with persistent storage (currently only supports OPFS). Requires both a web worker and a shared worker.

On browsers without SharedWorker support (e.g. Android Chrome), this adapter automatically falls back to single-tab mode. In single-tab mode:

  • Each tab runs independently with its own leader worker
  • Multi-tab synchronization is not available
  • Devtools are not supported

@seehttps://github.com/livestorejs/livestore/issues/321 - SharedWorker tracking issue

@seehttps://issues.chromium.org/issues/40290702 - Chromium SharedWorker bug

@example

import { makePersistedAdapter } from '@livestore/adapter-web'
import LiveStoreWorker from './livestore.worker.ts?worker'
import LiveStoreSharedWorker from '@livestore/adapter-web/shared-worker?sharedworker'
const adapter = makePersistedAdapter({
worker: LiveStoreWorker,
sharedWorker: LiveStoreSharedWorker,
storage: { type: 'opfs' },
})

makePersistedAdapter
({
storage: {
readonly type: "opfs";
readonly directory?: string | undefined;
}

Specifies where to persist data for this adapter

storage
: {
type: "opfs"
type
: 'opfs' },
worker: ((options: {
name: string;
}) => globalThis.Worker) | (new (options: {
name: string;
}) => globalThis.Worker)
worker
:
const LiveStoreWorker: new (options?: {
name?: string;
}) => Worker
LiveStoreWorker
,
sharedWorker: ((options: {
name: string;
}) => globalThis.SharedWorker) | (new (options: {
name: string;
}) => globalThis.SharedWorker)

This is mostly an implementation detail and needed to be exposed into app code due to a current Vite limitation (https://github.com/vitejs/vite/issues/8427).

In most cases this should look like:

import LiveStoreSharedWorker from '@livestore/adapter-web/shared-worker?sharedworker'
const adapter = makePersistedAdapter({
sharedWorker: LiveStoreSharedWorker,
// ...
})

sharedWorker
:
const LiveStoreSharedWorker: new (options?: {
name?: string;
}) => SharedWorker
LiveStoreSharedWorker
,
})
export const
const useAppStore: () => Resource<Store<any, {}>> & SolidApi
useAppStore
= () =>
useStore<any, {}, Schema<JsonValue>>(options: AccessorMaybe<RegistryStoreOptions<any, {}, Schema<JsonValue>>>): Resource<Store<any, {}>> & SolidApi

Returns a store resource that suspends until the store is loaded. The store is cached by its storeId in the StoreRegistry.

@example

import { Suspense } from 'solid-js'
function Issue(props: { issueId: string }) {
const store = useStore(issueStoreOptions(props.issueId))
const issues = store()?.useQuery(queryDb(tables.issue.select()))
return (
<Show when={store()}>
{(s) => <IssueView store={s()} />}
</Show>
)
}
// With Suspense boundary
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Issue issueId="abc123" />
</Suspense>
)
}

@returnsA Resource that resolves to the loaded store instance augmented with Solid hooks

useStore
({
CreateStoreOptions<TSchema extends LiveStoreSchema, TContext = {}, TSyncPayloadSchema extends Schema<any> = Schema<JsonValue>>.adapter: Adapter

Adapter used for data storage and synchronization.

adapter
,
CreateStoreOptions<any, {}, Schema<JsonValue>>.schema: any

The LiveStore schema defining tables, events, and materializers.

schema
,
CreateStoreOptions<TSchema extends LiveStoreSchema, TContext = {}, TSyncPayloadSchema extends Schema<any> = Schema<JsonValue>>.storeId: string

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

  • Valid characters: Only alphanumeric characters, underscores (_), and hyphens (-) are allowed. Must match /^[a-zA-Z0-9_-]+$/.
  • Globally unique: Use globally unique IDs (e.g., nanoid) to prevent collisions across stores.
  • Use namespaces: Prefix to avoid collisions and for easier identification when debugging (e.g., app-root, workspace-abc123, issue-456)

storeId
: 'default',
})
/** @jsxImportSource solid-js */
import { type
type Component<P extends Record<string, any> = {}> = (props: P) => JSX.Element

A general Component has no implicit children prop. If desired, you can specify one as in Component<{name: String, children: JSX.Element}>.

Component
,
function For<T extends readonly any[], U extends JSX.Element>(props: {
each: T | undefined | null | false;
fallback?: JSX.Element;
children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element

Creates a list elements from a list

it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned:

<For each={items} fallback={<div>No items</div>}>
{(item, index) => <div data-index={index()}>{item}</div>}
</For>

If you have a list with fixed indices and changing values, consider using <Index> instead.

For
} from 'solid-js'
import {
import visibleTodos$
visibleTodos$
} from './livestore/queries.ts'
import {
import events
events
, type
import tables
tables
} from './livestore/schema.ts'
import {
import useAppStore
useAppStore
} from './livestore/store.ts'
let
let currentStore: any
currentStore
:
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any

Obtain the return type of a function type

ReturnType
<typeof
import useAppStore
useAppStore
> | undefined
const
const handleToggle: (event: Event & {
currentTarget: HTMLInputElement;
}) => void
handleToggle
= (
event: Event & {
currentTarget: HTMLInputElement;
}
event
:
interface Event

The Event interface represents an event which takes place on an EventTarget.

MDN Reference

Event
& {
currentTarget: HTMLInputElement
currentTarget
:
interface HTMLInputElement

The HTMLInputElement interface provides special properties and methods for manipulating the options, layout, and presentation of elements.

MDN Reference

HTMLInputElement
}) => {
const
const store: any
store
=
let currentStore: any
currentStore
?.()
if (
const store: any
store
===
var undefined
undefined
) return
const
const id: string | undefined
id
=
event: Event & {
currentTarget: HTMLInputElement;
}
event
.
currentTarget: EventTarget & HTMLInputElement

The currentTarget read-only property of the Event interface identifies the element to which the event handler has been attached.

MDN Reference

Alias for event.target.

currentTarget
.
HTMLOrSVGElement.dataset: DOMStringMap
dataset
.
DOMStringMap[string]: string | undefined
todoId
const
const completed: string | undefined
completed
=
event: Event & {
currentTarget: HTMLInputElement;
}
event
.
currentTarget: EventTarget & HTMLInputElement

The currentTarget read-only property of the Event interface identifies the element to which the event handler has been attached.

MDN Reference

Alias for event.target.

currentTarget
.
HTMLOrSVGElement.dataset: DOMStringMap
dataset
.
DOMStringMap[string]: string | undefined
todoCompleted
if (
const id: string | undefined
id
===
var undefined
undefined
||
const completed: string | undefined
completed
===
var undefined
undefined
) return
const store: any
store
.
any
commit
(
const completed: string
completed
=== 'true' ?
import events
events
.
any
todoUncompleted
({
id: string
id
}) :
import events
events
.
any
todoCompleted
({
id: string
id
}))
}
const
const handleDelete: (event: MouseEvent & {
currentTarget: HTMLButtonElement;
}) => void
handleDelete
= (
event: MouseEvent & {
currentTarget: HTMLButtonElement;
}
event
:
interface MouseEvent

The MouseEvent interface represents events that occur due to the user interacting with a pointing device (such as a mouse). Common events using this interface include click, dblclick, mouseup, mousedown.

MDN Reference

MouseEvent
& {
currentTarget: HTMLButtonElement
currentTarget
:
interface HTMLButtonElement

The HTMLButtonElement interface provides properties and methods (beyond the regular HTMLElement interface it also has available to it by inheritance) for manipulating elements.

MDN Reference

HTMLButtonElement
}) => {
const
const store: any
store
=
let currentStore: any
currentStore
?.()
if (
const store: any
store
===
var undefined
undefined
) return
const
const id: string | undefined
id
=
event: MouseEvent & {
currentTarget: HTMLButtonElement;
}
event
.
currentTarget: EventTarget & HTMLButtonElement

The currentTarget read-only property of the Event interface identifies the element to which the event handler has been attached.

MDN Reference

Alias for event.target.

currentTarget
.
HTMLOrSVGElement.dataset: DOMStringMap
dataset
.
DOMStringMap[string]: string | undefined
todoId
if (
const id: string | undefined
id
===
var undefined
undefined
) return
const store: any
store
.
any
commit
(
import events
events
.
any
todoDeleted
({
id: string
id
,
deletedAt: Date
deletedAt
: new
var Date: DateConstructor
new () => Date (+3 overloads)
Date
() }))
}
export const
const MainSection: Component
MainSection
:
type Component<P extends Record<string, any> = {}> = (props: P) => JSX.Element

A general Component has no implicit children prop. If desired, you can specify one as in Component<{name: String, children: JSX.Element}>.

Component
= () => {
const
const store: any
store
=
import useAppStore
useAppStore
()
let currentStore: any
currentStore
=
const store: any
store
const
const todos: any
todos
=
const store: any
store
.
any
useQuery
(
import visibleTodos$
visibleTodos$
)
const
const todoItems: () => any
todoItems
= () =>
const todos: any
todos
() ?? ([] as (typeof
import tables
tables
.
any
todos
.
any
Type
)[])
return (
<
JSX.HTMLElementTags.section: JSX.HTMLAttributes<HTMLElement>
section
JSX.DOMAttributes<HTMLElement>.class?: string | undefined
class
="main">
<
JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
ul
JSX.DOMAttributes<T>.class?: string | undefined
class
="todo-list">
<
function For<T extends readonly any[], U extends JSX.Element>(props: {
each: T | undefined | null | false;
fallback?: JSX.Element;
children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element

Creates a list elements from a list

it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned:

<For each={items} fallback={<div>No items</div>}>
{(item, index) => <div data-index={index()}>{item}</div>}
</For>

If you have a list with fixed indices and changing values, consider using <Index> instead.

For
each: any
each
={
const todoItems: () => any
todoItems
()}>
{(
todo: any
todo
: typeof
import tables
tables
.
any
todos
.
any
Type
) => (
<
JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
li
>
<
JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
div
JSX.DOMAttributes<T>.class?: string | undefined
class
="view">
<
JSX.HTMLElementTags.input: JSX.InputHTMLAttributes<HTMLInputElement>
input
JSX.InputHTMLAttributes<HTMLInputElement>.type?: "number" | (string & {}) | "checkbox" | "button" | "color" | "date" | "datetime-local" | "email" | "file" | "hidden" | "image" | "month" | "password" | "radio" | "range" | "reset" | "search" | "submit" | "tel" | "text" | "time" | "url" | "week" | undefined
type
="checkbox"
JSX.DOMAttributes<T>.class?: string | undefined
class
="toggle"
JSX.InputHTMLAttributes<HTMLInputElement>.checked?: boolean | undefined
checked
={
todo: any
todo
.
any
completed
}
data-todo-id: any
data-todo-id
={
todo: any
todo
.
any
id
}
data-todo-completed: string
data-todo-completed
={
todo: any
todo
.
any
completed
=== true ? 'true' : 'false'}
JSX.CustomEventHandlersCamelCase<HTMLInputElement>.onChange?: JSX.ChangeEventHandlerUnion<HTMLInputElement, Event> | undefined
onChange
={
const handleToggle: (event: Event & {
currentTarget: HTMLInputElement;
}) => void
handleToggle
}
/>
<
JSX.HTMLElementTags.label: JSX.LabelHTMLAttributes<HTMLLabelElement>
label
>{
todo: any
todo
.
any
text
}</
JSX.HTMLElementTags.label: JSX.LabelHTMLAttributes<HTMLLabelElement>
label
>
<
JSX.HTMLElementTags.button: JSX.ButtonHTMLAttributes<HTMLButtonElement>
button
JSX.ButtonHTMLAttributes<HTMLButtonElement>.type?: "button" | "reset" | "submit" | "menu" | undefined
type
="button"
JSX.DOMAttributes<T>.class?: string | undefined
class
="destroy"
data-todo-id: any
data-todo-id
={
todo: any
todo
.
any
id
}
JSX.CustomEventHandlersCamelCase<HTMLButtonElement>.onClick?: JSX.EventHandlerUnion<HTMLButtonElement, MouseEvent, JSX.EventHandler<HTMLButtonElement, MouseEvent>> | undefined
onClick
={
const handleDelete: (event: MouseEvent & {
currentTarget: HTMLButtonElement;
}) => void
handleDelete
} />
</
JSX.HTMLElementTags.div: JSX.HTMLAttributes<HTMLDivElement>
div
>
</
JSX.HTMLElementTags.li: JSX.LiHTMLAttributes<HTMLLIElement>
li
>
)}
</
function For<T extends readonly any[], U extends JSX.Element>(props: {
each: T | undefined | null | false;
fallback?: JSX.Element;
children: (item: T[number], index: Accessor<number>) => U;
}): JSX.Element

Creates a list elements from a list

it receives a map function as its child that receives a list element and an accessor with the index and returns a JSX-Element; if the list is empty, an optional fallback is returned:

<For each={items} fallback={<div>No items</div>}>
{(item, index) => <div data-index={index()}>{item}</div>}
</For>

If you have a list with fixed indices and changing values, consider using <Index> instead.

For
>
</
JSX.HTMLElementTags.ul: JSX.HTMLAttributes<HTMLUListElement>
ul
>
</
JSX.HTMLElementTags.section: JSX.HTMLAttributes<HTMLElement>
section
>
)
}

You can control logging for Solid’s runtime helpers via optional options passed to getStore:

const
const adapter: Adapter
adapter
=
function makePersistedAdapter(options: WebAdapterOptions): Adapter

Creates a web adapter with persistent storage (currently only supports OPFS). Requires both a web worker and a shared worker.

On browsers without SharedWorker support (e.g. Android Chrome), this adapter automatically falls back to single-tab mode. In single-tab mode:

  • Each tab runs independently with its own leader worker
  • Multi-tab synchronization is not available
  • Devtools are not supported

@seehttps://github.com/livestorejs/livestore/issues/321 - SharedWorker tracking issue

@seehttps://issues.chromium.org/issues/40290702 - Chromium SharedWorker bug

@example

import { makePersistedAdapter } from '@livestore/adapter-web'
import LiveStoreWorker from './livestore.worker.ts?worker'
import LiveStoreSharedWorker from '@livestore/adapter-web/shared-worker?sharedworker'
const adapter = makePersistedAdapter({
worker: LiveStoreWorker,
sharedWorker: LiveStoreSharedWorker,
storage: { type: 'opfs' },
})

makePersistedAdapter
({
storage: {
readonly type: "opfs";
readonly directory?: string | undefined;
}

Specifies where to persist data for this adapter

storage
: {
type: "opfs"
type
: 'opfs' },
worker: ((options: {
name: string;
}) => globalThis.Worker) | (new (options: {
name: string;
}) => globalThis.Worker)
worker
:
const LiveStoreWorker: new (options?: {
name?: string;
}) => Worker
LiveStoreWorker
,
sharedWorker: ((options: {
name: string;
}) => globalThis.SharedWorker) | (new (options: {
name: string;
}) => globalThis.SharedWorker)

This is mostly an implementation detail and needed to be exposed into app code due to a current Vite limitation (https://github.com/vitejs/vite/issues/8427).

In most cases this should look like:

import LiveStoreSharedWorker from '@livestore/adapter-web/shared-worker?sharedworker'
const adapter = makePersistedAdapter({
sharedWorker: LiveStoreSharedWorker,
// ...
})

sharedWorker
:
const LiveStoreSharedWorker: new (options?: {
name?: string;
}) => SharedWorker
LiveStoreSharedWorker
,
})
export const
const useAppStore: () => Resource<Store<any, {}>> & SolidApi
useAppStore
= () =>
useStore<any, {}, Schema<JsonValue>>(options: AccessorMaybe<RegistryStoreOptions<any, {}, Schema<JsonValue>>>): Resource<Store<any, {}>> & SolidApi

Returns a store resource that suspends until the store is loaded. The store is cached by its storeId in the StoreRegistry.

@example

import { Suspense } from 'solid-js'
function Issue(props: { issueId: string }) {
const store = useStore(issueStoreOptions(props.issueId))
const issues = store()?.useQuery(queryDb(tables.issue.select()))
return (
<Show when={store()}>
{(s) => <IssueView store={s()} />}
</Show>
)
}
// With Suspense boundary
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Issue issueId="abc123" />
</Suspense>
)
}

@returnsA Resource that resolves to the loaded store instance augmented with Solid hooks

useStore
({
CreateStoreOptions<TSchema extends LiveStoreSchema, TContext = {}, TSyncPayloadSchema extends Schema<any> = Schema<JsonValue>>.adapter: Adapter

Adapter used for data storage and synchronization.

adapter
,
CreateStoreOptions<TSchema extends LiveStoreSchema, TContext = {}, TSyncPayloadSchema extends Schema<any> = Schema<JsonValue>>.storeId: string

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

  • Valid characters: Only alphanumeric characters, underscores (_), and hyphens (-) are allowed. Must match /^[a-zA-Z0-9_-]+$/.
  • Globally unique: Use globally unique IDs (e.g., nanoid) to prevent collisions across stores.
  • Use namespaces: Prefix to avoid collisions and for easier identification when debugging (e.g., app-root, workspace-abc123, issue-456)

storeId
: 'default',
// Optional: swap logger and minimum log level
logger?: Layer<never, never, never> | undefined

Optional Effect logger layer to control logging output.

logger
:
import Logger
Logger
.
const layer: <readonly [Logger.Logger<unknown, void>]>(loggers: readonly [Logger.Logger<unknown, void>], options?: {
readonly mergeWithExisting?: boolean | undefined;
} | undefined) => Layer<never, never, never>

Creates a Layer which will overwrite the current set of loggers with the specified array of loggers.

Details

If the specified array of loggers should be merged with the current set of loggers (instead of overwriting them), set mergeWithExisting to true.

Example (Providing logger layers)

import { Effect, Logger } from "effect"
// Single logger layer
const JsonLoggerLive = Logger.layer([Logger.consoleJson])
// Multiple loggers layer
const MultiLoggerLive = Logger.layer([
Logger.consoleJson,
Logger.consolePretty(),
Logger.formatStructured
])
// Merge with existing loggers
const AdditionalLoggerLive = Logger.layer(
[Logger.consoleJson],
{ mergeWithExisting: true }
)
// Using multiple logger formats
const jsonLogger = Logger.consoleJson
const prettyLogger = Logger.consolePretty()
const CustomLoggerLive = Logger.layer([jsonLogger, prettyLogger])
const program = Effect.log("Application started").pipe(
Effect.provide(CustomLoggerLive)
)

@since4.0.0

layer
([
import Logger
Logger
.
const consolePretty: (options?: {
readonly colors?: "auto" | boolean | undefined;
readonly stderr?: boolean | undefined;
readonly formatDate?: ((date: Date) => string) | undefined;
readonly mode?: "browser" | "tty" | "auto" | undefined;
}) => Logger.Logger<unknown, void>

A Logger which outputs logs in a "pretty" format and writes them to the console.

Details

For example, pretty output can render as [09:37:17.579] INFO (#1) label=0ms: hello followed by an annotation line such as key: value.

Example (Logging with pretty console output)

import { Effect, Logger } from "effect"
// Use the pretty console logger with default settings
const basicPretty = Effect.log("Hello Pretty Format").pipe(
Effect.provide(Logger.layer([Logger.consolePretty()]))
)
// Configure pretty logger options
const customPretty = Logger.consolePretty({
colors: true,
stderr: false,
mode: "tty",
formatDate: (date) => date.toLocaleTimeString()
})
// Perfect for development environment
const developmentProgram = Effect.gen(function*() {
yield* Effect.log("Application starting")
yield* Effect.logInfo("Database connected")
yield* Effect.logWarning("High memory usage detected")
}).pipe(
Effect.annotateLogs("environment", "development"),
Effect.withLogSpan("startup"),
Effect.provide(Logger.layer([customPretty]))
)
// Disable colors for CI/CD environments
const ciLogger = Logger.consolePretty({ colors: false })

@since4.0.0

consolePretty
()]),
logLevel?: LogLevel | undefined

Optional minimum log level for the runtime.

logLevel
: 'Info', // use "None" to disable logs
})
import {
import Events
Events
,
const makeSchema: <TInputSchema extends InputSchema>(inputSchema: TInputSchema) => FromInputSchema.DeriveSchema<TInputSchema>
makeSchema
,
import Schema
Schema
,
type SessionIdSymbol = typeof SessionIdSymbol
const SessionIdSymbol: typeof SessionIdSymbol

Can be used in queries to refer to the current session id. Will be replaced with the actual session id at runtime.

In client document table:

const uiState = State.SQLite.clientDocument({
name: 'ui_state',
schema: Schema.Struct({
theme: Schema.Literals(['dark', 'light', 'system']),
user: Schema.String,
showToolbar: Schema.Boolean,
}),
default: { value: defaultFrontendState, id: SessionIdSymbol },
})

Or in a client document query:

const query$ = queryDb(tables.uiState.get(SessionIdSymbol))

SessionIdSymbol
,
import State
State
} from '@livestore/livestore'
export const
const tables: {
todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema.Codec<boolean, number, never, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
...;
};
}>, State.SQLite.WithDefaults<...>, Schema.Struct<...>>;
uiState: State.SQLite.ClientDocumentTableDef<...>;
}
tables
= {
todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema.Codec<boolean, number, never, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
...;
};
}>, State.SQLite.WithDefaults<...>, Schema.Struct<...>>
todos
:
import State
State
.
import SQLite
SQLite
.
function table<"todos", {
readonly id: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema.Codec<string, string, never, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema.Codec<boolean, number, never, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
...;
};
}, Partial<...>>(args: {
...;
} & Partial<...>): State.SQLite.TableDef<...> (+2 overloads)

Creates a SQLite table definition from columns or an Effect Schema.

This function supports two main ways to define a table:

  1. Using explicit column definitions
  2. Using an Effect Schema (either the name property needs to be provided or the schema needs to have a title/identifier)