# Server-side clients

import { Tabs, TabItem } from '@astrojs/starlight/components';



import ServerSideClientDiagram from '../../_assets/diagrams/server-side-client.tldr?tldraw';

You can also use LiveStore on the server side e.g. via the `@livestore/adapter-node` adapter. This allows you to:
- have an up-to-date server-side SQLite database (read model)
- react to events / state changes on the server side (e.g. to send emails/push notifications)
- commit events on the server side (e.g. for sensitive/trusted operations)

<ServerSideClientDiagram />

Note about the schema: While the `events` schema needs to be shared across all clients, the `state` schema can be different for each client (e.g. to allow for a different SQLite table design on the server side).

## Example

<Tabs>
  <TabItem label="main.ts">

## `reference/syncing/server-side-clients/main.ts`

```ts filename="reference/syncing/server-side-clients/main.ts"
/** biome-ignore-all lint/correctness/noUnusedVariables: docs snippet keeps inline setup */
// ---cut---
import { makeAdapter } from '@livestore/adapter-node'
import { createStorePromise } from '@livestore/livestore'
import { makeWsSync } from '@livestore/sync-cf/client'

import { schema, tables } from './schema.ts'

const adapter = makeAdapter({
  storage: { type: 'fs', baseDirectory: 'tmp' },
  sync: { backend: makeWsSync({ url: 'ws://localhost:8787' }), onSyncError: 'shutdown' },
})

const store = await createStorePromise({
  adapter,
  schema,
  storeId: 'test',
  syncPayload: { authToken: 'insecure-token-change-me' },
})

const todos = store.query(tables.todos.where({ completed: false }))
```

### `reference/syncing/server-side-clients/schema.ts`

```ts filename="reference/syncing/server-side-clients/schema.ts"
import { makeSchema, State } from '@livestore/livestore'

const events = {}

const tables = {
  todos: State.SQLite.table({
    name: 'todos',
    columns: {
      id: State.SQLite.text({ primaryKey: true }),
      text: State.SQLite.text(),
      completed: State.SQLite.boolean({ default: false }),
    },
  }),
}

const state = State.SQLite.makeState({ tables, materializers: {} })

export const schema = makeSchema({ events, state })

export { tables }
```

</TabItem>
  <TabItem label="schema.ts">

## `reference/syncing/server-side-clients/schema.ts`

```ts filename="reference/syncing/server-side-clients/schema.ts"
import { makeSchema, State } from '@livestore/livestore'

const events = {}

const tables = {
  todos: State.SQLite.table({
    name: 'todos',
    columns: {
      id: State.SQLite.text({ primaryKey: true }),
      text: State.SQLite.text(),
      completed: State.SQLite.boolean({ default: false }),
    },
  }),
}

const state = State.SQLite.makeState({ tables, materializers: {} })

export const schema = makeSchema({ events, state })

export { tables }
```

</TabItem>
</Tabs>

## Further notes

### Cloudflare Workers

- The `@livestore/adapter-node` adapter doesn't yet work with Cloudflare Workers but you can follow [this issue](https://github.com/livestorejs/livestore/issues/266) for a Cloudflare adapter to enable this use case.
- Having a `@livestore/adapter-cf-worker` adapter could enable serverless server-side client scenarios.