Use when setting up a production database for Bknd. Covers SQLite file, LibSQL/Turso, Cloudflare D1, PostgreSQL, Neon, Supabase, and Xata configuration.
Set up and configure a production database for your Bknd application.
| Database | Best For | Platform Compatibility | Cost |
|---|---|---|---|
| SQLite File | VPS, Docker, single-server | Node.js, Bun | Free |
| LibSQL/Turso | Serverless, edge, global | All platforms | Free tier |
| Cloudflare D1 | Cloudflare Workers | Cloudflare only | Free tier |
| PostgreSQL | Complex queries, transactions | VPS, Docker | Self-hosted |
| Neon | Serverless Postgres | Vercel, Lambda | Free tier |
| Supabase | Postgres + extras | Any | Free tier |
| Xata | Serverless + search | Any | Free tier |
Best for: Single-server deployments with full control
// bknd.config.ts
export default {
app: (env) => ({
connection: {
url: env.DB_URL ?? "file:data.db", // Relative to cwd
},
}),
};
# Relative path (project directory)
DB_URL=file:data.db
# Absolute path (recommended for production)
DB_URL=file:/var/data/myapp/bknd.db
mkdir -p /var/data/myapp
# docker-compose.yml
services:
bknd:
volumes:
- bknd-data:/app/data
environment:
- DB_URL=file:/app/data/bknd.db
volumes:
bknd-data:
Best for: Serverless, edge deployments, global distribution
# macOS/Linux
curl -sSfL https://get.tur.so/install.sh | bash
# Authenticate
turso auth login
# Create database
turso db create my-bknd-db
# Optional: Specify region
turso db create my-bknd-db --location lax # Los Angeles
# Get connection URL
turso db show my-bknd-db --url
# Output: libsql://my-bknd-db-username.turso.io
# Create auth token
turso db tokens create my-bknd-db
# Output: eyJhbGciOi...
// bknd.config.ts
export default {
app: (env) => ({
connection: {
url: env.DB_URL, // libsql://...
authToken: env.DB_TOKEN,
},
}),
};
DB_URL=libsql://my-bknd-db-username.turso.io
DB_TOKEN=eyJhbGciOi...
Common regions: ams (Amsterdam), fra (Frankfurt), lax (LA), lhr (London), nrt (Tokyo), syd (Sydney)
turso db locations # List all regions
Best for: Cloudflare Workers deployments
wrangler d1 create my-bknd-db
Output:
Created D1 database 'my-bknd-db'
database_name = "my-bknd-db"
database_id = "abc123-def456-..."
name = "my-bknd-app"
main = "src/index.ts"
compatibility_date = "2024-01-01"
[[d1_databases]]
binding = "DB"
database_name = "my-bknd-db"
database_id = "abc123-def456-..."
// src/index.ts
import { hybrid, type CloudflareBkndConfig } from "bknd/adapter/cloudflare";
import { d1Sqlite } from "bknd/adapter/cloudflare";
export default hybrid<CloudflareBkndConfig>({
app: (env) => ({
connection: d1Sqlite({ binding: env.DB }),
isProduction: true,
}),
});
# List databases
wrangler d1 list
# Execute SQL (local dev)
wrangler d1 execute my-bknd-db --local --command "SELECT * FROM posts"
# Execute SQL (production)
wrangler d1 execute my-bknd-db --command "SELECT * FROM posts"
# Export backup
wrangler d1 backup create my-bknd-db
Best for: Complex queries, large datasets, existing Postgres infrastructure
npm install postgres
# or
npm install pg
Using postgres (recommended):
import { PostgresJsConnection } from "bknd/adapter/postgres";
export default {
app: (env) => ({
connection: new PostgresJsConnection({
connectionString: env.DATABASE_URL,
}),
}),
};
Using pg:
import { PgPostgresConnection } from "bknd/adapter/postgres";
export default {
app: (env) => ({
connection: new PgPostgresConnection({
connectionString: env.DATABASE_URL,
}),
}),
};
DATABASE_URL=postgresql://user:password@host:5432/database?sslmode=require
Best for: Vercel, serverless, auto-scaling Postgres
npm install kysely-neon
import { createCustomPostgresConnection } from "bknd";
import { NeonDialect } from "kysely-neon";
const neon = createCustomPostgresConnection("neon", NeonDialect);
export default {
app: (env) => ({
connection: neon({
connectionString: env.NEON_DATABASE_URL,
}),
}),
};
NEON_DATABASE_URL=postgres://user:password@ep-xxx.us-east-1.aws.neon.tech/neondb?sslmode=require
Best for: Full-featured Postgres with extras (auth, storage, realtime)
Use "Direct connection" (not pooler) for Bknd:
postgresql://postgres:[PASSWORD]@db.[PROJECT-REF].supabase.co:5432/postgres
export default {
app: (env) => ({
connection: {
url: env.SUPABASE_DB_URL,
},
}),
};
SUPABASE_DB_URL=postgresql://postgres:your-password@db.abcdefgh.supabase.co:5432/postgres
Best for: Serverless Postgres with built-in search
npm install @xata.io/kysely
import { createCustomPostgresConnection } from "bknd";
import { XataDialect } from "@xata.io/kysely";
const xata = createCustomPostgresConnection("xata", XataDialect);
export default {
app: (env) => ({
connection: xata({
apiKey: env.XATA_API_KEY,
workspace: "your-workspace",
database: "your-database",
}),
}),
};
After configuring your database, Bknd auto-syncs schema on first request. For manual control:
# Dry run (preview changes)
npx bknd sync --dry-run
# Apply changes
npx bknd sync
# Force sync (use with caution)
npx bknd sync --force
// test-connection.ts
import { app } from "bknd";
const bknd = app({
connection: {
url: process.env.DB_URL!,
authToken: process.env.DB_TOKEN,
},
});
async function test() {
await bknd.build();
console.log("Connection successful!");
console.log("Entities:", Object.keys(bknd.modules.data.entities));
process.exit(0);
}
test().catch((e) => {
console.error("Connection failed:", e);
process.exit(1);
});
Run:
npx tsx test-connection.ts
Problem: Can't connect to database
Fix:
Problem: Missing or invalid auth token
Fix:
# Generate new token
turso db tokens create my-bknd-db
# Set in environment
export DB_TOKEN="eyJhbGciOi..."
Problem: env.DB is undefined in Cloudflare Workers
Fix: Check wrangler.toml binding name matches code:
[[d1_databases]]
binding = "DB" # Must match env.DB
Problem: Connection fails without SSL
Fix: Add ?sslmode=require to connection string:
DATABASE_URL=postgresql://user:pass@host:5432/db?sslmode=require
Problem: Database not created
Fix:
# Turso
turso db create my-bknd-db
# D1
wrangler d1 create my-bknd-db
# PostgreSQL
createdb my-bknd-db
Problem: Migrations fail on production database
Fix:
# Preview changes first
npx bknd sync --dry-run
# If stuck, use --force (data loss possible!)
npx bknd sync --force --drop
# SQLite
sqlite3 data.db .dump > backup.sql
# Using API
curl http://localhost:3000/api/data/posts > posts.json
# Via seed function (recommended)
# See bknd-seed-data skill
# Direct SQL (SQLite to SQLite only)
cat backup.sql | turso db shell my-bknd-db
DO:
DON'T:
--force --drop without backups