# How to Initialize Logto with a Database: Complete Setup Guide

> Initialize Logto with a database easily. Set DB_URL and run 'pnpm cli db seed' to create schemas and roles for your Logto server setup. Get the guide now.

- Repository: [Logto/logto](https://github.com/logto-io/logto)
- Tags: how-to-guide
- Published: 2026-07-03

---

**Set the `DB_URL` environment variable to your PostgreSQL connection string and run `pnpm cli db seed` to create the schema, admin tenant, and default roles before starting the Logto server.**

Logto is an open-source identity and access management platform that persists all configuration, tenant data, and user records in PostgreSQL. To initialize Logto with a database, you must provide a valid database connection string and execute the seeding CLI command, which atomically creates tables and inserts the required bootstrap data. This guide explains the exact steps and source code implementation used in the `logto-io/logto` repository.

## Prerequisites

Before initializing Logto, ensure you have:

- A running PostgreSQL instance (version 14 or higher recommended)
- The `DB_URL` environment variable exported with a valid connection string
- Node.js and pnpm installed to run the CLI commands

## The Database Seeding Process

Logto requires a specific database schema and seed data to function as a multi-tenant OIDC provider. The initialization process is handled by the CLI command implemented in [`packages/cli/src/commands/database/seed/index.ts`](https://github.com/logto-io/logto/blob/main/packages/cli/src/commands/database/seed/index.ts).

### Step 1: Database Connection and Creation

The CLI first reads the `DB_URL` environment variable from [`packages/shared/src/node/env/GlobalValues.ts`](https://github.com/logto-io/logto/blob/main/packages/shared/src/node/env/GlobalValues.ts). If the target database does not exist, the function `createPoolAndDatabaseIfNeeded` automatically creates it before proceeding.

```bash
export DB_URL="postgres://postgres:your-password@localhost:5432/logto"

```

### Step 2: Schema Creation

The `seedByPool` function initiates a `slonik` transaction to ensure atomicity. Inside this transaction, `createTables` (defined in [`packages/cli/src/commands/database/seed/tables.ts`](https://github.com/logto-io/logto/blob/main/packages/cli/src/commands/database/seed/tables.ts)) executes SQL generated from the `@logto/schemas` definitions to build all required tables.

### Step 3: Data Seeding

After tables exist, `seedTables` inserts the essential runtime data:
- **Admin tenant**: The master tenant that holds management API credentials
- **Core roles**: Role definitions including `admin`, `user`, and `role admin` for RBAC
- **OIDC client templates**: Default configurations used by the UI to create new applications

If the `--cloud` flag is provided, `seedCloud` adds extra scopes and applications required for Logto Cloud. If `--test` is provided, `seedTest` loads large synthetic datasets useful for integration testing.

## Running the Seed Command

### Basic Seeding

Run the following to create the database schema and insert default data:

```bash
export DB_URL="postgres://postgres:your-password@localhost:5432/logto"
pnpm cli db seed

```

This command executes `seedByPool`, which wraps `createTables` and `seedTables` in a single transaction. If any step fails, the entire operation rolls back to prevent partial data persistence.

### Seed with Cloud Data

For Logto Cloud deployments or when you need cloud-specific configurations:

```bash
export DB_URL="postgres://postgres:your-password@localhost:5432/logto"
pnpm cli db seed --cloud

```

This triggers the `seedCloud` function in [`packages/cli/src/commands/database/seed/tables.ts`](https://github.com/logto-io/logto/blob/main/packages/cli/src/commands/database/seed/tables.ts), which inserts additional cloud scopes and records.

### Seed with Test Data

For CI environments or performance testing:

```bash
export DB_URL="postgres://postgres:your-password@localhost:5432/logto"
pnpm cli db seed --test

```

The `--test` flag invokes `seedTest` to populate the database with thousands of synthetic users and log entries.

## Docker Compose Initialization

When using Docker Compose, the entrypoint automatically handles database initialization before starting the server. The [`docker-compose.yml`](https://github.com/logto-io/logto/blob/main/docker-compose.yml) in the repository root specifies:

```yaml
entrypoint: ["sh", "-c", "npm run cli db seed -- --swe && npm start"]

```

This ensures the database is seeded with the `--swe` (skip when exists) flag before the Core server launches.

## Programmatic Seeding

If you need to initialize Logto from a Node.js script rather than the CLI, import the internal functions directly:

```typescript
import { createPoolAndDatabaseIfNeeded } from '@logto/cli/src/database.js';
import { seedByPool } from '@logto/cli/src/commands/database/seed/index.js';

async function initializeLogtoDatabase() {
  // Respects DB_URL environment variable
  const pool = await createPoolAndDatabaseIfNeeded();
  
  // Seed with default options
  await seedByPool(pool, { cloud: false, test: false });
  
  await pool.end();
  console.log('Database initialized successfully');
}

initializeLogtoDatabase().catch(console.error);

```

This approach uses the same `seedByPool` function that the CLI invokes, ensuring consistency between programmatic and command-line initialization.

## Summary

- **Export `DB_URL`**: Set your PostgreSQL connection string in the environment before running any commands.
- **Run `pnpm cli db seed`**: Creates the database if missing, builds the schema via `createTables`, and inserts required data via `seedTables`.
- **Atomic transactions**: All seeding operations in [`packages/cli/src/commands/database/seed/index.ts`](https://github.com/logto-io/logto/blob/main/packages/cli/src/commands/database/seed/index.ts) run inside a `slonik` transaction to prevent partial state.
- **Optional flags**: Use `--cloud` for Logto Cloud data or `--test` for synthetic test datasets.
- **Source locations**: Configuration reading happens in [`packages/shared/src/node/env/GlobalValues.ts`](https://github.com/logto-io/logto/blob/main/packages/shared/src/node/env/GlobalValues.ts), while table creation and seeding logic reside in [`packages/cli/src/commands/database/seed/tables.ts`](https://github.com/logto-io/logto/blob/main/packages/cli/src/commands/database/seed/tables.ts).

## Frequently Asked Questions

### What happens if I start Logto without seeding the database?

The Logto Core server checks for the existence of seeded data during startup. If the required admin tenant and core configurations are missing, the server aborts with the error message "Did you forget to seed your database?" as implemented in [`packages/core/src/libraries/logto-config.ts`](https://github.com/logto-io/logto/blob/main/packages/core/src/libraries/logto-config.ts).

### Can Logto create the PostgreSQL database automatically?

Yes. If the database specified in `DB_URL` does not exist, `createPoolAndDatabaseIfNeeded` creates it automatically before executing any schema migrations. This function runs before `seedByPool` in the initialization flow.

### What is the difference between `--cloud` and `--test` seeding flags?

The `--cloud` flag triggers `seedCloud` in [`packages/cli/src/commands/database/seed/tables.ts`](https://github.com/logto-io/logto/blob/main/packages/cli/src/commands/database/seed/tables.ts), which adds scopes and configurations specific to the Logto Cloud hosted service. The `--test` flag triggers `seedTest`, which loads large volumes of synthetic data for integration testing and performance benchmarking, not intended for production use.

### Is the database seeding operation atomic?

Yes. The entire seeding process runs inside a single `slonik` database transaction managed by `seedByPool`. If table creation fails or seed data insertion encounters an error, the transaction rolls back and the CLI exits without persisting partial changes, ensuring database consistency.