DarkDuck uses PostgreSQL via Drizzle ORM. There are three ways to run the database.

1. Embedded PostgreSQL (Default)

Zero config. If you don’t set DATABASE_URL, the server starts an embedded PostgreSQL instance automatically.
pnpm dev
On first start, the server:
  1. Creates ~/.darkduck/instances/default/db/ for storage
  2. Ensures the darkduck database exists
  3. Runs migrations automatically
  4. Starts serving requests
Data persists across restarts. To reset: rm -rf ~/.darkduck/instances/default/db. The Docker quickstart also uses embedded PostgreSQL by default.
Embedded mode is ideal for development and single-machine deployments. It requires no external services and starts instantly.

2. Local PostgreSQL (Docker)

For a full PostgreSQL server locally:
docker compose up -d
This starts PostgreSQL 17 on localhost:5432. Set the connection string:
cp .env.example .env
# DATABASE_URL=postgres://darkduck:darkduck@localhost:5432/darkduck
Push the schema:
DATABASE_URL=postgres://darkduck:darkduck@localhost:5432/darkduck \
  npx drizzle-kit push

3. Hosted PostgreSQL

For production, use a hosted provider like Supabase, Neon, or AWS RDS.
1

Create a database

Create a PostgreSQL 17 database with your provider.
2

Get the connection string

Copy the direct connection string (port 5432) for migrations and the pooled connection (port 6543) for the application.
3

Configure DarkDuck

Set DATABASE_URL in your .env or environment.
If using connection pooling, disable prepared statements:
// packages/db/src/client.ts
export function createDb(url: string) {
  const sql = postgres(url, { prepare: false });
  return drizzlePg(sql, { schema });
}
Use the direct connection (not pooled) for running migrations. Pooled connections may interfere with DDL statements.

Switching Between Modes

DATABASE_URLMode
Not setEmbedded PostgreSQL
postgres://...localhost...Local Docker PostgreSQL
postgres://...supabase.com...Hosted provider
The Drizzle schema (packages/db/src/schema/) is the same regardless of mode. Migrations run automatically on server start.

Backups

For embedded mode, back up the entire database directory:
cp -r ~/.darkduck/instances/default/db ~/.darkduck/backups/$(date +%Y%m%d)
For external PostgreSQL, use standard pg_dump:
pg_dump $DATABASE_URL > backup.sql