Neon
Neon is Sadie’s canonical production database. The serverless HTTP driver (@neondatabase/serverless) is stateless, has no pool to warm up, and runs happily on the Cloudflare worker that hosts the app.
Why Neon, not a pooled TCP connection
Section titled “Why Neon, not a pooled TCP connection”Sadie runs on Cloudflare Pages via OpenNext. That environment does not keep a persistent TCP pool between requests. A classic pg pool would open and close a socket per cold start, which is both slow and wasteful. The Neon HTTP driver sidesteps the problem: every query is a single stateless HTTP round-trip. It also means DATABASE_URL can be used from any region without a bouncer.
Branches on Neon are a production-grade staging story. You branch off main for preview deploys and flip back in seconds.
Option A: Neon MCP (recommended)
Section titled “Option A: Neon MCP (recommended)”If you have the Neon MCP installed in Claude Code, ask:
Create a Neon project called
sadiein my org, give me the pooled connection string.
The MCP returns a URL of the form:
postgresql://<user>:<password>@ep-xxxxxxxx-pooler.<region>.aws.neon.tech/<db>?sslmode=requirePaste it into .env.local as DATABASE_URL. The .neon.tech hostname auto-selects the HTTP driver.
Option B: Neon dashboard
Section titled “Option B: Neon dashboard”- Sign in at neon.tech.
- Create a new project. Region close to your users. Postgres 16.
- Copy the pooled connection string from the Dashboard. Use the pooled one. The direct endpoint works too, but the pooler is the sensible default for serverless.
- Paste into
.env.local.
DATABASE_URL=postgresql://USER:PASS@ep-xxxxxxxx-pooler.REGION.aws.neon.tech/DB?sslmode=requireApply the schema
Section titled “Apply the schema”pnpm db:migrateThat replays the hand-crafted migrations in packages/db/drizzle/ in order. The first one (0000_init.sql) creates every table. Subsequent ones (0001_*, 0002_mind_to_soul.sql) are preserving renames and backfills.
If this is a brand-new database and you want to skip the migration history and just diff the schema in one shot:
pnpm db:pushdb:push is destructive for renames. Use it on empty databases only. See Migrations for the tradeoff.
Preview branches for staging
Section titled “Preview branches for staging”Create a branch off main for every preview:
# via the Neon MCP:# "create a branch called preview-foo off main, give me the connection string"
# via the dashboard:# Branches → New branch → copy connection stringWire that branch’s URL into a Cloudflare Pages preview environment variable. The branch starts as a zero-cost copy of production state and accepts writes independently.
Driver override
Section titled “Driver override”The app auto-detects the driver by hostname. If you ever proxy Neon through a non-.neon.tech hostname, force the HTTP driver explicitly:
SADIE_DB_DRIVER=neon-httpThe reverse (forcing postgres-js against a Neon URL) is rarely useful but supported via SADIE_DB_DRIVER=postgres.
Connection shape reference
Section titled “Connection shape reference”See packages/db/src/client.ts for the exact driver selection logic. The short version:
- Hostname ends in
.neon.techor.neon.build→neon-http(stateless). - Anything else →
postgres-js(pooled TCP,SADIE_DB_POOL_MAXdefaults to 5).