# What is an ephemeral environment? > A copy of your app per pull request, deleted on merge. What previews cost on Vercel, Render, Railway and Heroku, and how to run them on your own server. Published 2026-10-30, by Nick Potts. For agents: [llms.txt](https://ployz.dev/llms.txt) indexes the Ployz docs as Markdown. **TL;DR:** An ephemeral environment is a full copy of your app that starts when a pull request opens, gets its own URL, and is deleted when the pull request closes. For a small team (20 pull requests a month, an app and a database, two days each), previews cost **about $13 to $18 a month** on Render, Railway, Heroku or DigitalOcean, and $0 extra on a server you already rent until its RAM is full. - **Pick Vercel if** your app is a frontend plus functions and the database lives elsewhere. Previews are included. - **Pick Render, Railway or DigitalOcean if** you already host there and open a handful of pull requests a month. Set an expiry on Render, and leave Railway's bot previews off. - **Pick Northflank if** you already run Kubernetes; Qovery and Bunnyshell are priced for companies, not solo developers. - **Pick your own server if** previews carry several services or stay open for days. The cost is RAM you already pay for. - **Pick Ployz, which I build, if** you want that on your own server without writing the scripts: a preview per pull request with its own HTTPS address, where you check what your coding agent built before it merges. ## What is an ephemeral environment? An ephemeral environment is a short-lived, isolated deployment of your app, made from one pull request or branch, with its own URL, config and often its own database. Reviewers click a link instead of pulling the branch, and when the pull request merges or closes, the environment is deleted, so nothing drifts and nothing keeps billing. The pattern has three parts: 1. **A trigger.** A pull request opens or a commit lands on a branch, and the platform builds that code. 2. **An address.** The environment gets a URL like `pr-123.example.com`, and a comment on the pull request links to it. 3. **A teardown.** Merge or close the pull request and the environment, its containers and its data go away. That's what separates it from a staging server, which is one long-lived environment everyone shares and that slowly stops matching production. The names vary. "Preview environment" is Vercel's, Render's and Ployz's term (Ployz's dashboard says PR environments). "Review app" is Heroku's, "PR environment" is Railway's, and "dynamic environment" is GitLab's for an environment "created in a CI/CD pipeline and used by only a single deployment" ([GitLab environments](https://docs.gitlab.com/ci/environments/)). The one real difference is scope. A Vercel preview copies your frontend and functions; a Render, Railway or Heroku preview copies the whole stack, including fresh databases. That's what "full-stack ephemeral environment" means. ## Why use them? Because reading a diff misses what the change looks like when it runs. What they help with, in my experience as a solo developer: - **Checking your own work on a real URL:** mobile Safari, real HTTPS, real environment variables. Local dev hides a lot. - **Showing someone a change:** send a link instead of a screen recording. - **Testing a migration against an empty database:** if it fails on a fresh schema, you find out before production does. What they don't replace: load testing, and testing against production-sized data. A preview with an empty database tells you nothing about a query on 40 million rows. ## What would your preview environments cost? Describe how your team works. Each preview is a copy of your services at the smallest size (about 512 MB each), billed only while the pull request is open. The own-server row assumes previews fit into 4 GB of spare RAM on your production server, and adds a Hetzner CX33 for every extra 8 GB. Ployz's Free plan covers that one server; with extra servers the row adds Ployz Pro, which is coming at $19 a month with 3 servers included and $5 for each one after that. *The interactive calculator is on the web page: https://ployz.dev/blog/ephemeral-environment* The calculator at four sizes, 512 MB per service: | Team | Preview hours | Render / Heroku | Railway | DigitalOcean | Own server + Ployz | |---|---|---|---|---|---| | Solo: 8 PRs, 2 services, 2 days | 384 | $7 | $6 | $5 | $0 | | Small: 20 PRs, 2 services, 2 days | 960 | $18 | $16 | $13 | $0 | | Growing: 40 PRs, 3 services, 3 days | 2,880 | $83 | $71 | $59 | $30 (one extra CX33, plus Pro) | | Busy: 60 PRs, 4 services, a week | 10,080 | $387 | $331 | $276 | $56 (three extra CX33, plus Pro) | The Render column is compute only; full-stack previews also need its $25 Pro workspace. For a solo developer, PaaS previews cost about as much as a sandwich. The gap opens when pull requests stay open for a week and each preview carries a worker, Redis and Postgres. That's also when a forgotten preview with no expiry turns into a monthly line item. ## What do previews cost on each platform? ### Vercel Vercel creates a preview deployment for every push to a non-production branch and every pull request, on all plans, with a branch URL and a per-commit URL ([Vercel environments](https://vercel.com/docs/deployments/environments)). There's **no separate preview fee**: previews use the same metered functions and CDN as production. Only your frontend and functions are copied, so databases are up to you. A push or merge to your production branch makes a production deployment and points your domains at it. Every other branch, pull request and `vercel` without `--prod` makes a preview on a generated URL. Each environment has its own variables, so previews can use a test database. | Vercel feature | Price | Source | |---|---|---| | Preview deployments | Included, usage metered like production | [Environments](https://vercel.com/docs/deployments/environments) | | Custom environments (e.g. `staging`) | Pro: 1 per project, Enterprise: 12, no extra cost | [Environments](https://vercel.com/docs/deployments/environments#pricing-and-limits) | | Password protection | $20/month per protected project | [Pro plan](https://vercel.com/docs/plans/pro-plan#paid-add-ons) | | Preview deployment suffix (your own domain on previews) | $100/month | [Pro plan](https://vercel.com/docs/plans/pro-plan#paid-add-ons) | For a Next.js frontend on a hosted database, Vercel previews are the best deal here. For a worker, a queue and Postgres, they cover only part of the app. The rest of the bill is in [Vercel pricing](https://ployz.dev/blog/vercel-pricing). ### Render Render bills preview resources "the same as other Render services", prorated by the second ([Render preview environments](https://render.com/docs/preview-environments)). Full-stack previews need the **$25 Pro workspace**; Hobby gets single-service previews only ([Render pricing](https://render.com/pricing)). | Render resource | Monthly price | Source | |---|---|---| | Pro workspace (needed for full-stack previews) | $25 + compute | [Render pricing](https://render.com/pricing) | | Starter instance, 0.5 CPU, 512 MB | $7 | [Render pricing](https://render.com/pricing) | | Postgres 0.1c-256mb | $6 | [Render pricing](https://render.com/pricing) | | Persistent disk | $0.25 per GB | [Render pricing](https://render.com/pricing) | - Turn previews on in `render.yaml` with `previews.generation: automatic` or `manual`. Manual previews need `[render preview]` in the pull request title. - Databases and disks are copied, but they "do not include data from their corresponding 'base' resource". - `previews.plan` (or `previewPlan` for databases) gives preview copies a smaller instance, which is the main lever on cost. - **Previews don't expire by default.** `previews.expireAfterDays` deletes one after that many days without a commit. Set it: a forgotten app, worker and database is about $20 a month, forever. More in [Render pricing](https://ployz.dev/blog/render-pricing). ### Railway Railway copies your environment when a pull request opens and deletes it "as soon as the PR is merged or closed" ([Railway environments](https://docs.railway.com/reference/environments)). Its billing docs are blunt: these environments "run real services that consume real resources", and with 5 open pull requests "you may be running 5x your normal workload" ([Understanding your bill](https://docs.railway.com/pricing/understanding-your-bill)). Usage costs **$10 per GB of RAM** and $20 per vCPU a month, billed per second, plus $0.15 per GB of volume ([Railway pricing](https://railway.com/pricing)). Services in PR environments get a domain automatically only if the matching base service has a Railway-provided domain. There's a toggle for bot pull requests (Dependabot, Renovate); leave it off unless you want every dependency bump to start a full copy of your stack. More in [Railway pricing](https://ployz.dev/blog/railway-pricing). ### Heroku "Dynos and add-ons used by review apps are charged in exactly the same way as for normal apps. Costs are pro-rated to the second" ([Heroku review apps](https://devcenter.heroku.com/articles/github-integration-review-apps)). Review apps default to the cheapest dyno on your plan, and each gets fresh add-ons. A Basic dyno is **$7 a month** and Essential-0 Postgres is $5 ([Heroku pricing](https://www.heroku.com/pricing)). Review apps need an `app.json`, Pipelines and the GitHub integration, and can delete themselves after 1, 2, 5, 14 or 30 days of inactivity. The `postdeploy` script in `app.json` runs once when the review app is created, which is the most complete seeding story here. Heroku itself is in maintenance mode, which I cover in [Heroku pricing](https://ployz.dev/blog/heroku-pricing), so I wouldn't start a new project there for review apps. ### DigitalOcean App Platform DigitalOcean does previews through a GitHub Action: `app_action` with `deploy_pr_preview` deploys a copy when a pull request opens and posts the URL, and a second workflow deletes it on close ([DigitalOcean docs](https://docs.digitalocean.com/products/app-platform/how-to/deploy-from-github-actions/)). Each preview bills like any app, "by the second, with a one-minute minimum": **$5 a month** for a 512 MiB container, and $7 for a dev database billed by the hour ([App Platform pricing](https://docs.digitalocean.com/products/app-platform/details/pricing/)). That makes it the cheapest per preview in the calculator, at the cost of maintaining two workflow files. More in [DigitalOcean pricing](https://ployz.dev/blog/digitalocean-pricing). ### Kubernetes tools: Northflank, Qovery, Bunnyshell These are built for teams with a Kubernetes budget. All three can create databases per preview. | Tool | What you pay for previews | Source | |---|---|---| | Northflank | Compute at $0.01667/vCPU-hour, $0.00833/GB-hour; smallest plan $2.70/month (0.1 vCPU, 256 MB). Previews can expire after a set lifetime. | [Northflank pricing](https://northflank.com/pricing), [preview blueprints](https://northflank.com/docs/v1/application/release/set-up-a-preview-environment) | | Qovery | $2,999/month (billed yearly), 20 users, up to 3 clusters; cloud costs billed separately | [Qovery pricing](https://www.qovery.com/pricing) | | Bunnyshell | $0.007 per minute per environment, stops when stopped or deleted; your cluster costs extra | [Bunnyshell pricing](https://www.bunnyshell.com/pricing/) | Bunnyshell's fee is easy to underestimate. $0.007 a minute is $0.42 an hour, so the calculator's default team (960 preview hours) pays about **$403 a month** in Bunnyshell fees before the cluster. Northflank's rates work out to about $12 per vCPU and $6 per GB of RAM a month, cheaper than Railway's, and I think it's the best of the three for a small team. ## How do you run ephemeral environments on your own server? You don't need Kubernetes. An ephemeral environment needs four things: build the branch, run its containers, point a hostname at them with HTTPS, and delete everything on close. One Linux server with Docker and a reverse proxy can do all four. The do-it-yourself version: 1. **Wildcard DNS.** Point `*.preview.example.com` at your server. 2. **A reverse proxy that issues certificates.** Caddy can get a certificate per hostname as requests arrive, so `pr-123.preview.example.com` gets HTTPS without config changes. 3. **A CI job per pull request.** On open or push, build the image and start containers with names and a network unique to that pull request, then add a route. 4. **A CI job on close.** Stop the containers, delete their volumes, remove the route. It works. It's also a few hundred lines of scripts you maintain, and the edge cases (two pushes at once, a failed build, a reopened pull request) are where it breaks. Self-hosted tools do it for you: | Tool | Git hosts | What to know | Source | |---|---|---|---| | Coolify | GitHub, GitLab, Bitbucket, Gitea | URL `{{pr_id}}.{{domain}}` by default, needs a wildcard DNS record, deleted when the PR closes or merges. Public fork PRs are blocked unless you allow them. | [Coolify previews](https://coolify.io/docs/applications/ci-cd/github/preview-deploy) | | Dokploy | GitHub | Off by default, 3 previews per app unless you raise it, free `traefik.me` domains if you don't set your own. Not recommended for public repos. | [Dokploy previews](https://docs.dokploy.com/docs/core/applications/preview-deployments) | | Dokku | Any, via CI | No built-in previews; its GitHub Action creates and destroys review apps per pull request. | [dokku/github-action](https://github.com/dokku/github-action) | | Your own CI scripts | Any | The four steps above. Full control, and you own every edge case. | | | Ployz | GitHub | A preview for every pull request with its own HTTPS address, one replica per service, deleted when the PR merges or closes. You pick which services get their own copy, and saved preview settings ship with the merge. | [Ployz previews](https://ployz.dev/docs/environments/preview-environments) | There's no self-hosted Vercel, but Next.js self-hosts on a Node.js server, a Docker image or a static export ([Next.js self-hosting](https://nextjs.org/docs/app/guides/self-hosting)), so you can keep the framework and replace the preview feature. If you came looking for a Heroku review apps alternative, it's the same table. Two rules whichever you pick. Don't build previews for pull requests from strangers, because a preview runs unreviewed code on your server. And don't give previews production credentials. ### What does it cost on your own server? Nothing extra until the server is full. At about 512 MB per service, an 8 GB server with production using half its RAM fits about **eight small preview services** at once. | Server | Specs | Monthly price | Source | |---|---|---|---| | Hetzner CX23 (Germany, Finland) | 2 vCPU, 4 GB RAM, 40 GB | $6.49 + about $0.60 IPv4 | [Hetzner price list](https://docs.hetzner.com/general/infrastructure-and-availability/price-adjustment/) | | Hetzner CX33 (Germany, Finland) | 4 vCPU, 8 GB RAM, 80 GB | $9.99 + about $0.60 IPv4 | [Hetzner price list](https://docs.hetzner.com/general/infrastructure-and-availability/price-adjustment/) | | Netcup VPS 500 | 2 vCPU, 4 GB RAM, 64 GB, traffic included | €8.26 incl. VAT (12-month term) | [netcup VPS](https://www.netcup.com/en/server/vps) | | Netcup VPS 1000 | 4 vCPU, 8 GB RAM, 128 GB | €14.50 incl. VAT (12-month term) | [netcup VPS](https://www.netcup.com/en/server/vps) | In the US, Netcup's Manassas datacenter or a DigitalOcean Droplet is the cheap option. How to set up a VPS covers the server half, and [PaaS pricing](https://ployz.dev/blog/paas-pricing) compares the platforms' whole bills. ## What happens to databases in preview environments? Every full-stack option here gives a preview its own fresh, empty database, not a copy of production's data. Seeding is up to you, through a seed script, a fixture file or a sanitized dump. - **Heroku** runs `postdeploy` from `app.json` once when the review app is created. - **Render** copies datastores without data; you write the seeding step. - **Ployz** gives a preview its own copy of each database you pick, with an empty volume, and runs a setup command like `pnpm db:seed` before it first starts. A database you don't pick is shared with production, data included. Don't point previews at your production database. A preview runs code nobody has approved yet, and one bad migration on a pull request becomes a production incident. ## Where Ployz fits The scripts in the do-it-yourself section are the part I wanted a platform for, so Ployz does it on servers you rent. Install the Ployz GitHub App, connect a repo, and every pull request gets [a preview environment](https://ployz.dev/features/preview-environments). - **Its own HTTPS address,** like `web-pr-142.acme-x7q2.ployz.app`, with no wildcard DNS to set up. - **You choose what's copied:** pick which services get their own copy. Copied databases start empty, and a setup command seeds them. - **Config ships with the code:** change a preview's settings (a new variable, a new service), save them, and they go live with the merge. - **Each push redeploys it,** and it's deleted when the pull request merges or closes. Bot pull requests are off by default. - **No meter:** previews are unlimited on every plan. Their cost is RAM. - **Where you check your agent's work:** when Claude Code, Codex or Cursor opens a pull request, its preview is a running copy you can click through before you merge. Removing a service or database waits for your approval. - **Staging too:** branch production into a `staging` environment with its own services and variables, then save changes back to production. Production gets the rest of the platform in the same dashboard: custom domains with https, monitoring, searchable logs, uptime checks and a restore point for every database. The Free plan covers one server. [Get started](https://ployz.dev/auth/github). ## FAQ ### Are preview, ephemeral and dynamic environments the same thing? Mostly, yes. They're different platforms' names for a per-branch copy of your app that's created and destroyed automatically. The real difference is scope: frontend-only (Vercel) or the whole stack with databases (Render, Railway, Heroku, Ployz). ### What's the difference between an ephemeral environment and staging? Staging is one long-lived environment that everyone shares; ephemeral environments are many, one per pull request, deleted on merge. Most teams use both, and I cover the long-lived kind in [staging environments](https://ployz.dev/blog/staging-environment). ### Do I need Kubernetes for ephemeral environments? No. A single Linux server with Docker, a reverse proxy and a CI job per pull request can build, serve and delete previews. Coolify, Dokploy, Dokku's GitHub Action and Ployz all do it without Kubernetes. ### Do preview environments copy production data? No platform here copies it by default. Render, Heroku and Ployz give previews fresh, empty databases, and you seed them with a script. ### How do I stop forgotten previews from costing money? Set an expiry. Render's `previews.expireAfterDays` and Heroku's inactivity timer delete idle previews; Railway and Ployz delete them when the pull request closes. On your own server, an idle preview costs RAM, not money. ## How I checked I checked every price on 2026-10-01 on each platform's own pricing pages and docs, linked next to each number. The team sizes and the 512 MB-per-service assumption are mine, not any platform's. I haven't measured preview RAM use across real apps. I build Ployz, so weigh the "Where Ployz fits" section with that in mind. Give every pull request a preview on your own server with Ployz: [get started](https://ployz.dev/auth/github).