Thanks to visit codestin.com
Credit goes to reactstarter.com

Skip to content

Database

The db/ workspace manages the data layer with Drizzle ORM and Neon PostgreSQL. In production, Cloudflare Hyperdrive pools and caches connections at the edge.

Workspace Structure

bash
db/
├── schema/             # Table definitions and relations
├── migrations/         # Auto-generated SQL migrations
├── seeds/              # Seed data scripts
├── scripts/            # Utilities (seed runner, export)
├── drizzle.config.ts   # Drizzle Kit configuration
└── index.ts            # Re-exports schema + DatabaseSchema type

Schema files are organized by domain – one file per entity group (e.g., user.ts contains the user, session, identity, and verification tables). All tables are re-exported from schema/index.ts.

Connection Architecture

The API worker connects to Neon through Cloudflare Hyperdrive, which provides connection pooling and optional query caching at the edge.

Two Hyperdrive bindings are available:

BindingCacheUse for
HYPERDRIVE_CACHED60 s query cacheRead-heavy queries where slight staleness is acceptable
HYPERDRIVE_DIRECTNoneWrites, real-time reads, anything requiring fresh data

Both are exposed in tRPC context as ctx.db (cached) and ctx.dbDirect (direct):

ts
// apps/api/lib/db.ts (simplified)
export function createDb(hyperdrive: Hyperdrive) {
  const client = postgres(hyperdrive.connectionString, {
    max: 1, // single connection per Worker isolate
    prepare: false, // required for Hyperdrive compatibility
  });
  return drizzle(client, { schema, casing: "snake_case" });
}

INFO

In development, Wrangler's getPlatformProxy() emulates the Hyperdrive bindings locally, resolving them to your DATABASE_URL. Your code uses the same HYPERDRIVE_CACHED / HYPERDRIVE_DIRECT bindings in both environments – no conditional connection logic needed.

Commands

Run from the repo root. Append :staging or :prod to target other environments.

CommandDescription
bun db:generateGenerate migration SQL from schema changes
bun db:migrateApply pending migrations
bun db:pushPush schema directly (skips migration files)
bun db:studioOpen Drizzle Studio browser UI
bun db:seedRun seed scripts
bun db:checkCheck for drift between schema and migrations
bun db:exportExport database via pg_dump to db/backups/
bun db:typecheckRun TypeScript type-checking on the db/ workspace

Environment Targeting

Database scripts select the environment through the ENVIRONMENT variable (falls back to NODE_ENV). Each environment loads env files in priority order:

.env.{env}.local  →  .env.local  →  .env

For example, bun db:push:staging loads .env.staging.local first. The DATABASE_URL variable must be a valid postgres:// or postgresql:// connection string.

See Environment Variables for full details.

Importing Schemas

The @repo/db package exports two entry points:

ts
import * as schema from "@repo/db"; // full schema + DatabaseSchema type
import { user, session } from "@repo/db/schema"; // individual tables