Database
Nitro ships a lightweight SQL layer powered by db0. It defaults to SQLite (.data/db.sqlite) and works out of the box in dev and Node.js production. Experimental — enable the flag.
import { defineConfig } from "nitro";
export default defineConfig({
experimental: { database: true },
});Usage
Import useDatabase() from nitro/database (no auto-imports in v3). It returns a connection; the optional name defaults to "default".
import { defineHandler } from "nitro";
import { useDatabase } from "nitro/database";
export default defineHandler(async () => {
const db = useDatabase();
await db.sql`CREATE TABLE IF NOT EXISTS users (
"id" TEXT PRIMARY KEY, "firstName" TEXT, "lastName" TEXT, "email" TEXT
)`;
const id = String(Math.round(Math.random() * 10_000));
await db.sql`INSERT INTO users VALUES (${id}, 'John', 'Doe', '')`;
const { rows } = await db.sql`SELECT * FROM users WHERE id = ${id}`;
return { rows };
});Connections are created lazily and cached per name.
Query APIs
// Tagged template with safe parameter binding
const { rows } = await db.sql`SELECT * FROM users WHERE id = ${id}`;
const res = await db.sql`INSERT INTO posts (title) VALUES (${"Hello"})`;
// res.rows, res.changes, res.lastInsertRowid
// Raw string execution
await db.exec("CREATE TABLE IF NOT EXISTS t (id TEXT)");
// Prepared statement
const stmt = db.prepare("SELECT * FROM users WHERE id = ?");
const result = await stmt.bind("1001").all();Always use
db.sqltagged templates (orprepare().bind()) for user input — they parameterize and prevent SQL injection.
Configuration
import { defineConfig } from "nitro";
export default defineConfig({
experimental: { database: true },
database: {
default: { connector: "sqlite", options: { name: "db" } },
users: {
connector: "postgresql",
options: { url: "postgresql://user:pass@host:5432/db" },
},
},
// Use a local SQLite db in development while prod uses Postgres
devDatabase: {
default: { connector: "sqlite", options: { name: "dev-db" } },
},
});Use a named connection with useDatabase("users").
Connectors
All db0 connectors are supported, including: sqlite / node-sqlite, better-sqlite3, sqlite3, bun / bun-sqlite, libsql (+ libsql-http/libsql-web/libsql-core), postgresql, mysql2, pglite, planetscale, neon, cloudflare-d1, and Cloudflare Hyperdrive variants. Connector-specific settings (url, host, name, ...) go under options, not the top level. Third-party libs (e.g. pg for postgresql) are auto-detected/installed and passed via the connector's lib option.
Key Points
- Requires
experimental.database: true; defaults to a zero-config SQLite connection. useDatabase()fromnitro/database(explicit import — no auto-imports in v3); names default to"default".- Prefer
db.sqltagged templates for safe, parameterized queries. devDatabasereplacesdatabaseentirely in dev (not merged per-name) — include every connection you need.- Integrates with db0-supported ORMs; prefer this layer over platform-specific DB bindings for portability.