Neon branching and scale-to-zero
How Neon separates storage from compute to give every preview deployment its own copy-on-write database branch that scales to zero when idle.
You’re shipping a web app in 2026, and every pull request your team opens gets its own preview URL: a full running copy of the app a reviewer can click through before anyone merges.
That setup raises two hard questions.
First, each preview needs its own data, so two reviewers testing two PRs don’t corrupt each other’s results.
How does every preview get an isolated copy?
Second, if there’s a database behind every open PR, are you paying for each one, even those nobody has touched in a week?
On a traditional Postgres server both are dealbreakers: a per-PR database is too slow to copy and too expensive to leave idle, so teams don’t bother.
Neon removes that ceiling, and a single architectural choice answers both questions at once.
The previous lesson pointed your DATABASE_URL at a Neon branch; this lesson explains what that branch is.
Storage and compute, pulled apart
Section titled “Storage and compute, pulled apart”Branching, the database-per-preview trick, and the bill that drops to zero all follow from one fact about how Neon is built.
A traditional Postgres server is one process welded to its disk. The running program parses your SQL, plans queries, and reads and writes rows; the data files it owns sit on a disk bolted to the same machine. They boot together, live together, and die together.
That welding shows up as three specific pains:
- Copying the database means physically copying the disk. To duplicate a 10 GB database you
pg_dumpand restore it elsewhere: minutes of work and a second, full 10 GB on disk. - An idle server still costs money. A database behind a preview nobody has touched in a week burns the same compute as one under load, because always-on is its only state.
- You can’t add a read-only copy without replicating everything. A second process to spread read traffic needs its own disk, so all the data has to be copied and kept in sync.
Neon splits the process apart from the disk. Storage becomes a log of page versions in durable cloud storage, independent of any running program. Compute becomes a stateless Postgres process the platform starts on demand and points at that storage. Kill it and the data is untouched; start a new one against the same storage and it picks up where the last left off.
Traditional Postgres
Neon
Each pain turns into its opposite:
- Storage is shared, so a second process needs no copy of the data. That is what makes branching cheap.
- Compute is disposable, so when nobody is querying, the platform throws the process away and you pay nothing. That is scale-to-zero.
- Many computes can read one storage, so a read-only replica is just another process pointed at the same log. Neon supports this for scaling reads, though the course never needs it.
Branches share storage, so they’re nearly free
Section titled “Branches share storage, so they’re nearly free”A branch is a new compute pointed at a snapshot of a parent’s storage at a moment in time. It’s copy-on-write : the branch shares every existing page with its parent and copies nothing up front. Only when you change a page, by inserting a row or updating a value, does that one page get written fresh and kept separate. Everything you haven’t touched is still, physically, the parent’s pages.
So copying a 10 GB database the old way takes pg_dump, a restore, and a fresh 10 GB on disk; branching it on Neon takes under a second and roughly zero added storage, because the branch shares all 10 GB and has changed nothing.
You pay storage only for the pages your branch diverges on, so a branch you barely touch costs almost nothing to keep.
One thing about branches trips up nearly everyone. A branch captures its parent as it was at the moment you created it, and then the two go their separate ways. This is what point-in-time means, and it has real consequences:
A branch is not a live mirror of its parent. Rows the parent gains after you branch never show up, so an old branch shows old data; if a new production row isn’t appearing in a branch, the branch was cut before that row existed. The independence runs the other way too, and that’s what makes branches safe: rows your branch writes never flow back to the parent. You can fill a branch with garbage or drop a table, and the parent doesn’t feel it.
That safety is what makes branching worth building a workflow around. Here’s what it unlocks, each expanded in the sections that follow:
- A branch per preview deployment. Every open PR gets its own isolated, prod-shaped database.
- Two long-lived branches as your baseline. A
productionbranch that real users hit, and astagingbranch forked off it that lives indefinitely. This pair is the course’s default setup. - Migration rehearsal. Before running a destructive migration against production, branch it, run the scary thing on the branch, inspect the result, and throw the branch away if it went wrong. The branch is your undo button; the mechanics come in the migrations chapter.
These branches are created by the platform and the integration we’re about to meet, not by a command you type.
A database branch for every preview
Section titled “A database branch for every preview”This is the direct answer to the question we opened with: how does every preview get its own data? Follow one pull request from “opened” to “merged.”
PR opened. A developer pushes a Git branch and opens a pull request on GitHub. The database side is unchanged: production and staging exist, with no preview branch yet.
Neon branch created. The Vercel–Neon integration sees the new deployment and creates a Neon branch off the parent, named something like preview/<git-branch>. It’s copy-on-write, so it shares the parent’s storage and costs almost nothing.
Preview deployed with the branch’s URL. Vercel builds the preview and injects that branch’s connection string as the deployment’s DATABASE_URL. The preview app now talks to its own private database, so seeding or mutating it can’t touch production or any other PR.
Iterate safely. The developer pushes more commits, runs migrations against the preview branch, and QA clicks through real, isolated data.
PR merged or closed → branch deleted. With auto-delete enabled, the integration tears the preview branch down and reclaims the storage its diverged pages used. Back to just production and staging.
A database appears for the life of a PR and vanishes when it’s done. That teardown is what makes the pattern affordable.
It also replaces the single shared staging database, a well-known anti-pattern. With one staging database and two PRs in flight, reviewer A seeds test invoices, reviewer B’s destructive test drops a table A relied on, and a third migration leaves it half-broken, until nobody trusts what they see. Shared staging degrades because everyone writes to it and no one owns it. A branch per PR gives every preview a clean, production-shaped database that exactly one PR can touch, cheap enough to keep idle one per open pull request.
As of 2026 the Vercel–Neon integration comes in two flavors, differing only in who deletes the branch:
- Neon-managed: you switch on “automatically delete obsolete branches,” and cleanup runs the next time a preview deploys.
- Vercel-managed: the branch is deleted when Vercel removes the matching deployment, on Vercel’s retention policy, which defaults to roughly six months.
The deployment chapter owns the wiring; carry one watch-out from here: auto-delete is a setting you have to turn on. Leave it off and preview branches accumulate until your project holds the database of every PR you ever opened.
How the preview app opens a connection over that injected URL is the next lesson’s subject.
Compute sleeps when nobody’s looking
Section titled “Compute sleeps when nobody’s looking”Because a Neon compute holds no permanent state, the platform can do something a welded-together server never could: after a stretch of no activity, it suspends the compute entirely and the process goes away. While it’s gone you pay nothing for compute, and your data is safe: it was never in the process, it sits in storage, untouched. The moment a query arrives, the platform spins up a fresh compute, points it at the same storage, and serves the query. The database fell asleep and woke up, and nothing was lost. The current numbers, as of mid-2026:
- Idle window: after about five minutes with no activity, the compute suspends. On paid (Scale) plans this is a dial you can turn, from one minute up to never suspending. On the free tier the five-minute window is fixed.
- Wake time (the cold start ): roughly 300–800 milliseconds to resume, with total time-to-first-query usually between half a second and a second.
An idle preview branch with no traffic bills you for storage only, because its compute has dropped to zero. That is what makes a branch per pull request sustainable. Ten open pull requests are not ten databases burning compute around the clock; they are ten cheap storage snapshots whose compute flickers on only when someone opens that preview, then drops back to zero. Branching makes the copy free, and scale-to-zero makes the idle free.
Scale-to-zero is a trade: the first query after a suspend pays the wake latency; every query after that, on the warm compute, is fast. The whole cost lands on that first query, and you decide per branch whether it’s acceptable there.
One honest limit. Neon’s free plan gives you roughly 100 compute-hours per project a month, half a gigabyte of storage, and around ten branches. The exact numbers drift, so check the pricing page in the resources below for current figures. That is plenty to learn this model on and run a side project, but not sized for live production traffic, where real load burns through the compute-hours and you will need a paid plan.
The shape of a production Neon project
Section titled “The shape of a production Neon project”Pull the pieces together and a recognizable shape falls out, one you should be able to read off a real project at a glance.
DATABASE_URL points here · kept warm
- A Neon project holding a
productionprimary branch, the one yourDATABASE_URLpoints at in production, and a long-livedstagingbranch forked off it. - A Vercel–Neon integration that cuts an ephemeral branch per preview deployment, injects that branch’s connection string into the preview, and, with auto-delete on, removes the branch afterward.
- Production compute tuned to stay warm so no real user waits through a cold start, while preview and dev branches scale to zero, where the savings outweigh the wake latency.
Look at production in that tree and notice what protects it: only a name.
production is just a branch by convention.
The platform won’t stop anyone from running a destructive migration straight against it, no “are you sure,” no technical guard of any kind.
What protects it is discipline: branch it, test the change on the branch, then apply it for real.
Three things this section leaves for later: provisioning a project and wiring the integration (deployment chapter), the branch-run-promote migration discipline (migrations chapter), and how your application code connects to whichever branch URL it’s handed (the next lesson).
Check your understanding
Section titled “Check your understanding”Now put the model to work: map a real situation to the right move, and clear up the two misconceptions that cause the most trouble.
Branching is your undo button. Cut a branch off production, run the destructive migration there, and inspect the result. If it’s wrong, throw the branch away and production never knew. (The branch, run, promote workflow itself is the migrations chapter.)
A shared staging database is the problem here; a database per PR solves it. Each preview gets its own isolated, prod-shaped branch, so one PR’s test data can’t corrupt another’s.
The first request after an idle period is waking a scaled-to-zero compute. That’s fine for dev and previews, but not for users. Tune production to stay warm, with a longer or disabled idle window, so real traffic never pays the wake latency.
Preview branches don’t clean themselves up unless you tell them to. Turn on auto-delete so each branch is torn down when its PR closes, and the storage its diverged pages used gets reclaimed instead of creeping.
Read the situation, then reach for the Neon feature that fits. The two questions below cover the misconceptions worth getting right.
On Monday you create a branch off production. On Tuesday, three new rows are inserted into production — nothing else touches the branch. When you query the branch on Wednesday, what does it return?
production as it changes.production.production into the branch.production’s Tuesday writes stay on production and never appear in it. The same independence runs the other way, which is the whole point of a branch: anything you write to the branch never leaks back to production, so you can experiment freely.A preview branch has sat with zero traffic for the last hour — nobody opened its preview. The branch still holds the few pages it diverged from production. Which part of it is Neon billing you for during that idle hour?
Where to read more
Section titled “Where to read more”These are the canonical pages worth opening, especially for the numbers in this lesson, which drift over time, so trust the docs over any figure printed here.
The canonical reference for the idle window and wake latency — the numbers that move.
The copy-on-write model in depth: how a branch shares its parent's storage.
The integration that creates a database branch for every Vercel preview deployment.
The authoritative source for free-tier limits and compute-hour allowances.
A one-minute interactive demo: branch a 1 TB database, change rows, and revert — copy-on-write made tangible.
A distributed-systems engineer's deep dive into the storage/compute split — for when you want the layer below this lesson.