# Node adapter

Works with Node.js, Bun and Deno.

## Example


## `reference/platform-adapters/node-adapter/adapter.ts`

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

const adapter = makeAdapter({
  storage: { type: 'fs' },
  // or in-memory:
  // storage: { type: 'in-memory' },
  sync: { backend: makeWsSync({ url: 'ws://localhost:8787' }) },
  // To enable devtools:
  // devtools: { schemaPath: new URL('./schema.ts', import.meta.url) },
})
```

## Resetting local persistence

During development you can instruct the adapter to wipe the locally persisted state and eventlog databases on startup:


## `reference/platform-adapters/node-adapter/reset-persistence.ts`

```ts filename="reference/platform-adapters/node-adapter/reset-persistence.ts"
/** biome-ignore-all lint/correctness/noUnusedVariables: docs snippet keeps inline adapter */
// ---cut---
import { makeAdapter } from '@livestore/adapter-node'

const resetPersistence = process.env.NODE_ENV !== 'production' && Boolean(process.env.RESET_LIVESTORE)

const adapter = makeAdapter({
  storage: { type: 'fs' },
  resetPersistence,
})
```

:::caution
This will delete all local data for the given `storeId` and `clientId`. It only clears local persistence and does not reset any connected sync backend. Only enable it for debugging scenarios.
:::

### Worker adapter

The worker adapter can be used for more advanced scenarios where it's preferable to reduce the load of the main thread and run persistence/syncing in a worker thread.


## `reference/platform-adapters/node-adapter/worker-main.ts`

```ts filename="reference/platform-adapters/node-adapter/worker-main.ts"
/** biome-ignore-all lint/correctness/noUnusedVariables: snippet keeps adapter inline for docs */
// ---cut---
import { makeWorkerAdapter } from '@livestore/adapter-node'

const adapter = makeWorkerAdapter({
  storage: { type: 'fs' },
  workerUrl: new URL('./livestore.worker.js', import.meta.url),
})
```


## `reference/platform-adapters/node-adapter/worker-worker.ts`

```ts filename="reference/platform-adapters/node-adapter/worker-worker.ts"
import { makeWorker } from '@livestore/adapter-node/worker'
import { makeWsSync } from '@livestore/sync-cf/client'

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

makeWorker({
  schema,
  sync: { backend: makeWsSync({ url: 'ws://localhost:8787' }) },
})
```

### `reference/platform-adapters/node-adapter/schema.ts`

```ts filename="reference/platform-adapters/node-adapter/schema.ts"
import { defineMaterializer, Events, makeSchema, Schema, State } from '@livestore/livestore'

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 }),
    },
  }),
} as const

const events = {
  todoCreated: Events.synced({
    name: 'v1.TodoCreated',
    schema: Schema.Struct({ id: Schema.String, text: Schema.String }),
  }),
} as const

const materializers = State.SQLite.materializers(events, {
  [events.todoCreated.name]: defineMaterializer(events.todoCreated, ({ id, text }) =>
    tables.todos.insert({ id, text, completed: false }),
  ),
})

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

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

#### Logging

You can control what the Node worker logs and how it's formatted.
Pass two optional options to `makeWorker`:

- `logger` — where/format of logs (e.g. pretty console output)
- `logLevel` — how verbose logs are (`LogLevel.None` silences logs)


## `reference/platform-adapters/node-adapter/worker-logging.ts`

```ts filename="reference/platform-adapters/node-adapter/worker-logging.ts"
import { makeWorker } from '@livestore/adapter-node/worker'
import { Logger, LogLevel } from '@livestore/utils/effect'

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

makeWorker({
  schema,
  // readable console output by thread name
  logger: Logger.prettyWithThread('livestore-node-leader-thread'),
  // choose verbosity: None | Error | Warning | Info | Debug
  logLevel: LogLevel.Info,
})
```

### `reference/platform-adapters/node-adapter/schema.ts`

```ts filename="reference/platform-adapters/node-adapter/schema.ts"
import { defineMaterializer, Events, makeSchema, Schema, State } from '@livestore/livestore'

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 }),
    },
  }),
} as const

const events = {
  todoCreated: Events.synced({
    name: 'v1.TodoCreated',
    schema: Schema.Struct({ id: Schema.String, text: Schema.String }),
  }),
} as const

const materializers = State.SQLite.materializers(events, {
  [events.todoCreated.name]: defineMaterializer(events.todoCreated, ({ id, text }) =>
    tables.todos.insert({ id, text, completed: false }),
  ),
})

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

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

Tips:
- Use `LogLevel.None` to keep test output quiet.
- Keep the default (Debug) when diagnosing issues.