Neon local DB (opt-in)
Docker is the default local database and stays that way — see Golden Seed (Local DB). This page is for developers who would rather point local dev at a golden-seeded Neon branch instead of a docker volume. It is entirely opt-in: nothing changes for anyone who doesn't run the command, and the opt-in lives in a file on your machine, never in the repo.
Why you might want it
- Always current, always golden. The branch forks from the golden parent, which is reseeded from
devtools/db/seed_data.sql. Nobun run db.seed, no volume that drifts behind newer migrations, nothe or_permissions table does not existwedge in a fresh worktree. - Fixtures the docker volume doesn't have. The golden parent carries the Salesforce and HubSpot
or_integrationrows on vendor 0, so CRM/workflow surfaces are drivable locally — including theplaywright/workflowsCRM specs, which cannot run against a docker DB with no integrations at all. - Zero docker. Useful for onboarding and for cloud/remote sessions.
The trade is a slower boot (~+20s) and per-connection TLS. Interactive DX over raw speed was a deliberate call; E2E CI keeps using the local Postgres for that reason.
What it costs
Neon's per-project branch allowance is an included amount, not a hard cap — extra branches are billed (~$1.50/branch-month), not blocked. One branch per developer is noise next to the preview fleet. Idle branches are archived by Neon automatically (older than 14 days and untouched for 24 hours); re-running the command unarchives yours.
Opt in
You need a NEON_API_KEY with access to the previews Neon project. Export it in your shell profile, then:
bun run db.neonThat ensures a branch named dev-<you> off the golden parent, waits for Neon's asynchronous branch operations to actually finish, writes the pointer to ~/.onramp/db.env (mode 0600), mirrors it into the current worktree's .env, turns off the flags local can't serve (below), and migrates to your worktree's head.
Then bun run dev as usual — it prints the branch and host it connected to.
One branch per developer, shared by all your worktrees. That is the same model as the old shared docker volume and it is safe under expand-and-contract: expand migrations are additive, so any worktree can migrate the shared branch forward. Use --branch <name> if you genuinely need a separate one.
bun run db.neon --reset # throw away local changes, refork from golden
bun run db.neon list # branch + where the pointer points
bun run db.neon --print-exports # for a shell that doesn't load .env
bun run db.neon rm # delete the branch and the pointerOpt out
Delete the pointer, or override for a single run:
rm ~/.onramp/db.env # permanent: back to docker
ONRAMP_DB=docker bun run dev # one run onlyThen the usual docker path applies (bun run db.up && bun run db.seed).
What the pointer is, and why it's a machine file
ONRAMP_DATABASE_* are read from the process environment, and their defaults point at the local docker Postgres. Bun auto-loads the repo-root .env for bun run scripts, which is how the identity reaches Flask, pytest, the migration CLI and Playwright.
A per-worktree .env alone is not enough: with dozens of worktrees coming and going, a developer who opted into Neon weeks ago silently lands back on a stale docker volume in every new worktree — and the unused Neon branch then gets archived for inactivity. So the machine-level ~/.onramp/db.env is the source of truth and bun run dev mirrors it into whatever worktree you're in.
Flags local can't serve
The golden parent has some feature flags armed for previews, which run infrastructure a laptop doesn't. db.neon turns these off on your branch:
| flag | why local can't have it |
|---|---|
crm_lambda_data_source | routes CRM reads to the broker lambda, and renders a different trigger component |
rbac_enforcement | the seed grants no role assignments, so the engine denies every policy-declared endpoint |
rbac_vendor_managed | requires rbac_enforcement |
Same exclusion list devtools/db/build_seed.sh section 6 applies when it builds the seed for local and CI. If a future flag needs the same treatment, add it to INFRA_GATED_FEATURE_CODES in devtools/db/dev-branch.ts.
Notes
- The app connects through Neon's pooled endpoint and migrations run unpooled — the same split
devtools/db/preview-branch.tsuses, because PgBouncer's transaction pooling is wrong for alembic's session-scoped DDL. flask db upgradereporting "Golden parent is AHEAD of this worktree" is normal on a branch that is behindmain: the branch is seeded at the parent's head and only newer migrations from your worktree would apply.reseed-neon.tsand the preview sweeper both act onpr-*branches only, so adev-*branch survives reseeds and sweeps.- The read-only SQL tool works out of the box:
or_readonly_user's local-dev password is baked into the golden parent and written into the pointer.