2025-11-20 | PreviewProof Team
Per-Preview Database vs. Shared Dev Database: How to Choose
The most consequential decision in setting up preview environments isn’t which preview tool to use. It’s whether each PR gets its own database, or whether all previews share one long-lived dev database. Both approaches have teams running them with reasonable success. They’re also wildly different in cost, performance, blast radius, and what bugs they let through.
Most teams end up with a hybrid eventually, but you have to start somewhere. Here’s a framework for picking.
The two models
Per-preview database. Every PR gets a freshly provisioned, isolated database — Postgres, MySQL, or a managed equivalent like Neon or Supabase branches. Migrations and seeds run at boot. The database lives for the life of the preview, then tears down on PR close.
Shared dev database. All previews connect to one long-lived dev database. Migrations are applied manually or through a controlled process. Seed data is whatever’s in there. Survives across PRs.
These look like minor variations. They aren’t. The implications cascade through cost, isolation, debugging, and team dynamics in ways that are hard to reverse.
What per-preview gets you
True isolation. Two reviewers can’t affect each other’s data. The destructive change one PR makes can’t break another.
Realistic migration testing. Every preview runs migrations from scratch against your seed. Migrations breaking against empty databases is more common than people realize. Migration patterns for preview environments.
Reproducible bug reports. “I saw this on the preview” is meaningful when the seed is deterministic and the database is fresh.
Clean teardown. No “what’s this orphan record from a PR we merged six months ago” mysteries.
Compliance simplicity. Per-preview, synthetic seed, torn down on merge — easy to explain to security review. The data plane has a short, defined lifecycle.
What per-preview costs you
Boot time. Provisioning a database, applying migrations, running seeds — the slowest step in most pipelines. 30–120 seconds is typical.
Money. 50 active PRs means 50 database instances. The bill is real. Cost-aware preview environments.
Resource pressure. Disk, RAM, connections. A team with 30 active PRs against Postgres-on-Kubernetes saturates a node faster than expected. Managed services push the cost onto the vendor.
Operational complexity. Provisioning, migration, per-env secrets, connection pooling, lifecycle. None hard, all work.
What shared gets you
Speed. No database to provision. The app boots and connects to an existing, warm, migrated, seeded database. Boot time is just app boot time.
Cost. One database. Predictable bill.
Realistic data accumulation. Shared databases drift toward looking like production — organic edge cases that synthetic seeds miss.
Operational simplicity. One thing to back up, monitor, upgrade.
What shared costs you
Coupling. Two PRs with conflicting schema changes fight when their migrations run. The losing PR rebases on the winner’s migration.
Contention. PR A drops a table that PR B’s code expects, PR B breaks. The shared database becomes a coordination point.
Contamination. A PR that creates 10K test users leaves them for the next reviewer. A data-corrupting bug in PR A corrupts every PR’s data. The “let’s reset the dev database” ritual nobody enjoys.
False positives. A PR’s preview looks fine because data it depends on already exists — would have broken on a fresh boot. You find out in production.
Migration risk. A bad migration on the shared database breaks every preview until fixed.
Compliance complexity. A long-lived database with unclear lifecycle is harder to reason about in security review than a per-PR ephemeral one.
The decision framework
Run through these dimensions, weight by what your team cares about, and the answer usually emerges.
Data volume
If behavior is shaped by data volume — analytics, search ranking, ML scoring — per-preview is hard because volume is slow to seed. Shared (or hybrid with shared reference data) tends to win.
If behavior is mostly stateless — settings pages, simple CRUD — per-preview is fine. Seed lightly.
Migration frequency
Rare migrations, shared is reasonable. Frequent migrations, multiple per PR, per-preview is much safer. Shared databases under heavy migration pressure become a coordination nightmare.
Team size
3 engineers with 5 active PRs can run a shared database fine. 30 engineers with 80 active PRs cannot — per-preview isolation isn’t optional at that scale.
Cost-per-preview budget
Hard cap on per-PR cost? Per-preview Postgres may not fit. Hybrid (per-preview app, shared database) is a real option. So is “previews only on labeled PRs.”
App behavior shaped by data
App behaves the same given any reasonable data (“list of things with CRUD”)? Shared is fine. App logic depends on the specifics (billing prorations, multi-tenant config, workflow state machines)? Per-preview lets you control what’s there.
Worked examples
Typical SaaS, mid-sized team, mostly CRUD. Per-preview with synthetic seed. Isolation is worth the cost, the seed is small enough to be fast.
Multi-tenant B2B with frequent schema changes. Per-preview, full stop. Migration coordination on a shared database with five teams is a recurring outage source.
Analytics-heavy app, large reference data. Hybrid. Per-preview transactional database plus a shared read-only reference database. Reset reference quarterly.
Three-person pre-seed startup. Shared dev database. Coordination cost is zero. Migrate when you cross 8 engineers or 20 active PRs.
Federal contractor. Per-preview, synthetic seed, full lifecycle audit. Shared is hard to defend in security review. Federal contractor guide.
The hybrid pattern
Many teams end up with a hybrid: per-preview transactional database (each PR has its own users, projects, orders) on top of a shared reference database (currencies, country codes, taxonomies, ML artifacts).
You get most of per-preview’s isolation without paying to regenerate large reference data. The cost is operational complexity — two database lifecycles, two connection pools, two migration regimes.
Worth it when reference data is genuinely large (gigabytes) or expensive to generate (model artifacts, derived analytics). Overkill when it isn’t.
Our default recommendation
For most teams, most of the time: per-preview database, fully synthetic seed, deterministic, torn down on PR close. The isolation is worth the cost. The migration realism is worth the boot time. The compliance story is worth the operational work.
Move to shared only when you’ve hit a specific cost or boot-time constraint you can articulate and per-preview can’t satisfy. “Shared because we never thought about it” is the wrong reason and the source of most pain we see.
If you’d rather not build the per-preview database lifecycle yourself — provisioning, migration, seeding, teardown — that’s what PreviewProof handles by default, with the option to point at a shared reference database for data you don’t want regenerated. The trade-offs above hold regardless of which tool you pick. If your shared dev database is working, keep it. The decision framework is the part that matters.