Somewhere right now, a developer is describing a user-interface change in the text of a pull request — "moved the button, fixed the spacing, try it with an empty cart" — while the reviewer squints at a diff and tries to picture it. The entire ritual is a workaround for a missing thing: a live URL where the change is already running.
In 2026 that workaround is expiring. Vercel and Netlify made per-PR preview URLs automatic years ago, and the rest of the market has followed: Render, Railway, Northflank, Okteto, Qovery, Aptible, and the self-hosted pair Coolify and Dokploy all ship some form of "every pull request gets a live environment." Northflank's 2026 roundup of preview-environment platforms lists ten of them. Analyst forecasts widely cited this year expect 80 percent of software engineering organizations to run dedicated platform teams by 2026, up from 55 percent in 2025 — and per-PR environments are one of the first things those teams stand up.
So here is the verdict up front for any git-push platform that still deploys only its default branch: the gap is not deploying a branch. Any tenant can already push a branch and get it running with manual effort. The gap is the automatic lifecycle — open on PR, comment the URL back, die on merge — plus the cost discipline and the database strategy that make that lifecycle safe to leave running unattended. Everything below prices that gap concretely.
| Lifecycle step | Manual per-branch deploy | Automatic preview lifecycle |
|---|---|---|
| Trigger | Someone remembers to push the branch to the platform | PR webhook opens the environment with zero human action |
| Build | Hand-configured service, copied env vars, fingers crossed | Blueprint or manifest renders the full stack identically every time |
| URL | Passed around in chat, goes stale | Unique per-PR URL posted back as a PR comment by a bot |
| Feedback | "Works on my machine" plus screenshots | Reviewers click through the real app against real services |
| Teardown | Forgotten; the environment bills quietly for months | PR close or merge destroys everything within minutes |
The left column is a demo trick. The right column is infrastructure. The rest of this post is about what the right column costs to build.
How the mainstream implements it
Every implementation answers the same five questions: what triggers a preview, what the URL looks like, what destroys it, what happens to the database, and what you pay for. The answers cluster into three families.
Git-native SaaS: Vercel, Netlify, Render, Railway. Vercel and Netlify set the baseline years ago — push a branch, open a PR, get a URL, no configuration. Render follows the same shape with one explicit flag: previewsEnabled: true in render.yaml renders a full copy of the blueprint's services per PR under a {service}-pr-{number} pattern, with an IS_PULL_REQUEST environment variable so app code can tell preview from production. Railway's PR Environments arrive through its GitHub integration and add one cost-aware refinement worth stealing: focused PR environments deploy only the services whose code actually changed, which matters enormously for monorepos where a full clone would spin up a dozen untouched services per PR.
Kubernetes-native: Okteto, Northflank, Qovery. Okteto provisions each preview as its own Kubernetes namespace and wires the lifecycle through GitHub Actions: one workflow deploys the preview and posts the URL, a companion workflow using the destroy-preview action tears the namespace down when the PR closes. Northflank offers full-stack per-branch previews triggered via API, CLI, GitOps, or plain git pushes, with teardown tied to the PR lifecycle. Qovery's own comparison table of this market is admirably honest about the hard part: nearly everybody claims preview environments per PR, but scheduled auto-stop for non-production environments is only partial across most vendors — you build the off-switch yourself.
Self-hosted: Coolify, Dokploy, Aptible. Coolify watches the repository for pull and merge requests, spins up an isolated temporary deployment with its own URL when one opens, and destroys the container on merge or close to reclaim resources. Dokploy supports the same review-app flow with an API for triggering deployments manually when teams want a custom workflow. Aptible described the identical pattern on its own infrastructure in 2025: short-lived apps and databases that spin up on PR open and tear down on PR close, giving engineers a production-like target with minimal effort.
| Platform | Trigger | URL scheme | Teardown | Database story | Billing unit |
|---|---|---|---|---|---|
| Vercel / Netlify | Automatic on push and PR | Per-deployment hash URL | Automatic, retained per plan | Serverless / branched data | Per seat plus usage |
| Render | previewsEnabled in blueprint | {service}-pr-{number} | On PR close | Optional ephemeral DB copy | Per service, prorated by the second |
| Railway | GitHub integration | Ephemeral per-PR URL | On PR close | Pair with a branched DB | Per service usage |
| Okteto | GitHub Actions workflow | Per-namespace subdomain | destroy-preview action | Namespace-scoped services | Per namespace resources |
| Northflank | API, CLI, GitOps, or git | Per-branch URL | Tied to PR lifecycle | Full-stack clone incl. data | Per workload |
| Coolify / Dokploy | PR and MR webhooks | Unique per-preview URL | Destroyed on merge or close | Containers or attached DB | Your own server capacity |
Two details in that table deserve emphasis because they generalize. First, GitHub's Deployments API has a transient_environment flag that marks an environment as ephemeral so the UI auto-cleans it — competitors from Railway to Render all converge on this because it is the expected UX, and any new implementation should speak it. Second, Render prorates preview services by the second, which is the only sane billing primitive for resources that live for tens of hours: monthly flat rates would make every preview feel expensive, while per-second billing makes short-lived previews nearly free and puts the cost spotlight exactly where it belongs — on environments that never die.
The cost math, worked
The formula is simple, which is why teams get it wrong by skipping one term:
monthly preview cost = PRs per month x average PR lifetime in days x services per preview x unit cost per service-day, plus databases.
Take a concrete, typical team: 60 pull requests a month, each open 2.5 days on average, so about 5 previews are alive at any moment. Each preview clones a standard three-service stack — web, API, worker — where each service would cost about 25 USD per month (roughly 0.82 USD per service-day), plus one small database at about 15 USD per month (roughly 0.49 USD per day). One preview-day then costs 3 x 0.82 + 0.49 = 2.95 USD. The team burns 150 preview-days a month, so the total is about 443 USD per month — the price of a single mid-tier production database, buying every reviewer a live staging link on every PR.
Now the sensitivity, because no team is exactly that team:
- Focused deploys beat full clones. If only the changed service deploys per PR and the rest is shared staging — Railway's focused-environments idea — the same 150 preview-days cost about 150 x 0.82 = 123 USD per month, a bit over a quarter of the full-clone price. For monorepos this is the single biggest lever.
- Auto-stop beats both. Preview traffic is human traffic: reviewers click links during work hours. Stopping compute overnight and on weekends removes roughly two-thirds of idle hours. Qovery's comparison admits most vendors only partially automate this, so whoever builds the scheduler captures the savings.
- The failure mode is forgetting. Twenty stale environments nobody closed, each holding a full-stack clone at roughly 2.95 USD per preview-day, cost about 1,770 USD per month — four times the working set, buying literally nothing. This is the "quietly accrues idle cost" scenario, and it is why teardown automation is not a nice-to-have: it is the control that bounds the entire budget. A preview system without guaranteed teardown is an uncapped liability with a nice URL feature attached.
The honest summary: previews are cheap when they are short-lived and scoped, and ruinous only when teardown is manual. The cost argument against building them collapses the moment destruction is automatic — which reframes the engineering problem from "can we afford this" to "can we guarantee deletion."
The database is the hard part
Stateless services are the easy half of a preview. The database is where every implementation in the table above makes its most opinionated choice, because there are exactly three options and each one breaks somewhere:
| Strategy | How it works | When it shines | When it breaks |
|---|---|---|---|
| Blank ephemeral database | Fresh empty DB per preview, seeded by migrations | Schema-change PRs; tests that need isolation | Reviewers see an empty app; seed scripts rot |
| Production-data clone | Snapshot copied at preview creation | Content-heavy or data-dependent reviews | Slow for large datasets; PII in every clone |
| Database branch per PR | Copy-on-write branch (e.g. Neon-style) | Instant, cheap, production-like data | Requires a branching-capable provider; branch sprawl needs its own janitor |
Render's documented pattern shows the pragmatic middle path: the blueprint provisions an ephemeral database per preview, the app reads IS_PULL_REQUEST to pick the preview connection string, and an initialDeployHook seeds it — the community's canonical example pipes pg_dump from the source database straight into the preview on first deploy. That is a production clone implemented as a seed step: good enough for small datasets, visibly inadequate past a few gigabytes, which is exactly the point where teams graduate to branching providers.
The rule of thumb: start with blank-plus-seed because it is provider-independent and forces seed scripts to stay healthy — rotting seeds are a pre-existing condition the preview system merely diagnoses. Move to clones or branches when reviewers can no longer evaluate the change without realistic data, and treat PII handling in clones as a compliance feature, not an afterthought: a preview fleet multiplies every data-governance shortcut by the number of open PRs.
The build checklist for a git-push PaaS
For a platform whose git-push flow today deploys the default branch and nothing else, here is the ordered work, with each step marked by whether a tenant can already do it manually:
- PR webhook intake (new). Listen for opened, synchronize, and closed PR events. Nothing downstream exists without this trigger, so it comes first.
- Isolated build from blueprint (partially manual today). Render the same manifest that defines production — services, env vars, plans — parameterized by PR number. Deterministic rendering is what separates "a preview" from "someone's snowflake staging."
- Unique URL plus TLS (manual today). Wildcard domain, per-PR subdomain, automatic certificate. Reviewers will not click through certificate warnings, so TLS provisioning is on the critical path, not polish.
- Comment-back bot (new). Post the URL to the PR via the GitHub Deployments API with the
transient_environmentflag set, so the platform's UI and GitHub's UI agree about what is ephemeral. - Database provisioning (manual today). Blank-plus-seed first, per the previous section. This is the longest pole: everything else is plumbing, this is product judgment.
- Guaranteed teardown (new). Destroy on merge or close, plus a reaper that sweeps anything older than a TTL regardless of webhook delivery. Build the reaper before launch, not after the first 1,770 USD surprise bill — webhooks get lost, the sweeper is the actual guarantee.
Explicit deferrals: scheduled auto-stop (big savings, but only once previews exist), focused monorepo-aware deploys (build after measuring how many services actually change per PR), production-data cloning (build when reviewers complain about empty states, not before). The minimum lovable preview is steps 1 through 4 plus blank-database 5 and the reaper half of 6 — a weekend-scale project on top of an existing git-push pipeline, which is precisely why "we don't have one yet" reads as a roadmap choice rather than a technical barrier.
Why this is baseline now
LinearB's 2026 benchmarks analyzed over 8.1 million pull requests across more than 4,800 organizations — the review queue is where engineering time actually goes, so moving verification into the PR itself, as a clickable environment instead of a described diff, pays back across every one of those reviews. The platforms above have converged on the same lifecycle shape because the shape is downstream of the webhook: open, build, comment, destroy. There is no longer a design question, only a build queue.
For a self-hosted, open-source PaaS, that convergence is good news twice over. The whole lifecycle — webhooks, blueprint rendering, wildcard TLS, Deployments API comments, TTL reapers — runs happily on machines you own, with no per-seat preview tax owed to anyone. And per-second economics favor the owner-operator most of all: short-lived previews on hardware already paid for are the closest thing to free that staging environments have ever been.
Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own. Per-PR preview environments are on the roadmap: if short-lived, fully torn-down staging per pull request is the feature that would get your team to switch, star the repo on GitHub and tell us what your preview stack needs.



