Docs / Database
Database
The starter uses Drizzle ORM with Postgres. Schema is TypeScript; migrations are generated by Drizzle Kit; the dev workflow is db push.
Layout #
db/
schema/ — schema definitions, one file per domain
index.ts — exports the `db` client
drizzle.config.ts — Drizzle Kit config (driver, schema path, output dir)The db client is the only thing your app imports from db/. Server code calls it directly; client code never touches the database.
Dev workflow: db push #
For local development:
pnpm db:pushThis compares your TypeScript schema to the local database and applies the diff. Fast iteration; no migration files generated.
Production workflow: migrations #
For environments you care about (staging, prod):
pnpm db:generate # writes a new migration file under db/migrations/
pnpm db:migrate # applies pending migrationsCommit migration files. Review them before merging — Drizzle Kit generates the SQL but you own it.
Adding a table #
- Define it in a new file under
db/schema/:
import { pgTable, text, timestamp } from "drizzle-orm/pg-core";
export const widgets = pgTable("widgets", {
id: text("id").primaryKey(),
name: text("name").notNull(),
createdAt: timestamp("created_at").defaultNow().notNull(),
});-
Export it from
db/schema/index.ts. -
Run
pnpm db:pushin dev (ordb:generate+db:migratefor prod). -
Use it:
import { db } from "@/db";
import { widgets } from "@/db/schema";
const all = await db.select().from(widgets);Connection pooling #
The starter uses the postgres driver (not pg), which handles pooling internally. In serverless environments (Vercel, etc.), set DATABASE_URL to a pooler-aware connection string.
Seeding #
There's no built-in seed script. If you need one, add scripts/seed.ts and a pnpm seed entry — the pattern is unopinionated by design.