Extending the database schema
How to add new tables with Drizzle, generate migrations, and keep the @repo/database package coherent across every template variant.
Every LaunchApp template shares the same @repo/database package. Tables are defined in packages/database/src/schema/, one file per domain (auth.ts, billing.ts, organization.ts, and so on). This layout keeps the schema browsable and makes it obvious where new fields belong.
Adding a new table
Start by creating a new file under packages/database/src/schema/ for your domain. Drizzle uses TypeScript-native table definitions — no separate DSL, no codegen step from an external schema file:
import { pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
import { user } from "./auth";
export const project = pgTable("project", {
id: uuid("id").primaryKey().defaultRandom(),
ownerId: text("owner_id")
.notNull()
.references(() => user.id, { onDelete: "cascade" }),
name: text("name").notNull(),
createdAt: timestamp("created_at").notNull().defaultNow(),
});
Re-export the new table from packages/database/src/schema/index.ts so both the API and the web app can type-check queries against it.
Generating the migration
Run pnpm db:generate to diff your schema against the current migration state. Drizzle writes a new SQL file under packages/database/drizzle/ plus a snapshot JSON. Commit both files — migrations are content-addressed, so renaming or reordering them breaks every downstream deploy.
When the PR merges, run pnpm db:migrate against each environment (locally, staging, production). In CI we recommend a pre-deploy step that runs migrations before the new process starts serving traffic.
Keeping variants in sync
Because all template variants (React Router, Next.js, Nuxt, SvelteKit) consume the same @repo/database package, schema changes land once and propagate everywhere. This is one of the reasons the templates stay feature-equivalent even as individual frontends diverge in their rendering model. When you add a table, every variant gets it on the next sync.