---
title: Local development
description: Run the database on your own machine, give it a schema, and generate types.
---

The Zeitlos CLI runs a local database
so you can test your database code using the Zeitlos SDK unchanged locally on your machine.

To start the local development environment run:

```bash title="Terminal"
npx @zeitlosapp/cli dev
```

Requires **Node 22.5+**. It writes `ZEITLOS_DATABASE_URL` and `ZEITLOS_DATABASE_KEY` into
`.env.local`, so `createClient()` is zero-config locally exactly as it is in production.

## Give the local database a schema

Schema is not defined in code, so a fresh local database starts empty. Create tables through
the local MCP server, whose port is printed at startup:

```bash title="Terminal"
claude mcp add --transport http zeitlos-local http://localhost:7312/mcp
```

Then either ask your assistant for the tables your code needs, or mirror an existing cloud
project:

:::prompt
Using the production Zeitlos MCP, list the tables in project `my-app` and describe each one.
Then recreate that exact schema in the local database via the `zeitlos-local` MCP.
:::

That copies **schema, not data** — ask for specific rows too if you want sample data. See
[MCP server](/getting-started/mcp-server/).

## Generate types

Once the local database has a schema, generate a typed `Database` from it:

```bash title="Terminal"
npx @zeitlosapp/cli gen types
```

Regenerate whenever the schema changes. See [Type your tables](/database/quickstart/#type-your-tables).

## Settings

Local development is configured in `zeitlos.dev.json` at your project root. You can use it to configure your local development instance.

```json title="zeitlos.dev.json"
{
  "database": { "enabled": false },
  "ports": { "database": 7310 }
}
```

| Key                | Purpose                                                              |
| ------------------ | -------------------------------------------------------------------- |
| `database.enabled` | Can be used to disable the database emulator. `true` by default |
| `ports.database`   | Change the port of the database emulator to listen on.                  |

> [!NOTE]
> The file configures local development only. Nothing in it affects your deployed project —
> those settings live in the dashboard. Auth has its own keys in the same file; see
> [Authentication → Local development](/authentication/local-development/).

## Troubleshooting

### `createClient()` throws `config_error`

The SDK found no URL or key, which means `.env.local` never reached `process.env`. Next.js and
Vite load it automatically; a plain `node script.js`, some test runners and custom servers might
not.

Either load it yourself:

```bash title="Terminal"
node --env-file=.env.local script.js
```

…or pass the values explicitly, which also covers a non-default port:

```ts title="lib/db.ts"
import { createClient } from '@zeitlosapp/sdk';

export const db = createClient({
  url: process.env.ZEITLOS_DATABASE_URL,
  key: process.env.ZEITLOS_DATABASE_KEY,
});
```

You can disable modifying the `.env.local` file by using the `--no-env` parameter:

```bash title="Terminal"
npx @zeitlosapp/cli dev --no-env
```

### Database calls fail in the browser

They always will — the database is server-side only, locally as well as in production. Move
the call into a server component, route handler or server action. See
[Create a client](/database/quickstart/#create-a-client).
