Neon Setup
Neon provides serverless Postgres with auto-scaling and branching. The free tier is enough for development and small production deployments.
Create a project
- neon.tech → Create project.
- Pick a region matching your Vercel + Supabase regions.
- Name your branch (default
main).
Connection strings
Neon gives you two connection strings per database:
- Pooled (
...-pooler.region.aws.neon.tech) — go-to for serverless functions. Use asDATABASE_URL. - Direct (
...region.aws.neon.tech) — set asDATABASE_URL_UNPOOLED.
Both include ?sslmode=require.
DATABASE_URLThe Prisma schema does not declare a directUrl, so Prisma migrations run against DATABASE_URL (the pooled URL), not DATABASE_URL_UNPOOLED. Keep DATABASE_URL_UNPOOLED set for forward-compatibility, but it isn't wired into the schema today. If you hit pooler issues during migration, point DATABASE_URL at the direct connection for the duration of the migration.
Schema initialization
Run from a shell with both env vars set:
pnpm db:push # apply schema (no migration history needed)
pnpm db:seed # provision the demo project + admin user
db:push is idempotent. Re-run after schema changes. Production deployments that need migration history use db:migrate locally + db:deploy in CI.
Branching for environments
Neon supports DB branches — copy-on-write forks of the main DB. Use them for:
- Preview deploys — every Vercel preview deploy gets a Neon branch with a fresh copy of production data, automatically discarded on PR close.
- Staging environments — a long-lived branch for the staging Krios instance. Promote to prod by merging the branch back.
Vercel + Neon native integration handles this automatically when both are connected. See Neon's "Vercel integration" docs for the setup.
Connection pooling
Neon's pooler runs PgBouncer in transaction mode. This is the right choice for serverless — short-lived connections multiplexed onto the pool. Krios's Prisma config already uses it via the pooled URL.
For self-hosted Krios with high traffic, run your own PgBouncer in front of Postgres or use Neon's pooled URL even off-Vercel.
Migration sequence
When you change prisma/schema.prisma:
# Local (db:migrate already expands to `prisma migrate dev`)
pnpm db:migrate --name describe_change
# Commit prisma/migrations/
git add prisma/migrations
git commit -m "schema: add CustomFieldType"
# CI / production
pnpm db:deploy
Or, for fast-iteration projects without migration history:
pnpm db:push # local
# In production: same command, but be aware that destructive changes (column drops) need --accept-data-loss
Backups + recovery
Neon snapshots the database continuously. Point-in-time-restore is in the Neon dashboard:
- Settings → PITR. Pick a timestamp; Neon creates a new branch from that point.
For larger deployments, schedule a nightly pg_dump to S3 as a belt-and-braces redundancy.
Tuning
- Increase
connection_limiton the pooled URL via the query string (?connection_limit=20) for high-throughput admin operations. - Enable autoscaling in the Neon dashboard so the compute scales up under load and down when idle (free tier suspends after 5 min of inactivity).
Common pitfalls
- Using the unpooled URL in serverless. You'll exhaust connections under load. Pool URL only.
- Forgetting
sslmode=require. Neon rejects unencrypted connections. Both URLs include it by default. - Running
db:push --accept-data-lossin production. It's destructive — only run with explicit migration intent.