Back to Blog
5 min read

Extending the database schema

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.

  • database
  • drizzle
LT

LaunchApp Team

Feb 17, 2025

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.