How to Initialize Logto with a Database: Complete Setup Guide

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.

Step 1: Database Connection and Creation

The CLI first reads the DB_URL environment variable from packages/shared/src/node/env/GlobalValues.ts. If the target database does not exist, the function createPoolAndDatabaseIfNeeded automatically creates it before proceeding.

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) 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:

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:

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, which inserts additional cloud scopes and records.

Seed with Test Data

For CI environments or performance testing:

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 in the repository root specifies:

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:

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

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.

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, 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →