How-to guide

How to give every pull request a preview environment

Learn how to give every pull request its own short-lived preview environment: build an image, deploy it, seed test data, gate access, and tear it down.

By the Cloudverg engineering team · · 6 min read

Why this matters

How to give every pull request a preview environment is mostly repeatable plumbing. A reviewer should not have to pull a branch, install dependencies and guess which environment variables matter. A preview URL removes that friction. The app runs the pull request's container image with the same config shape as staging, so design, product and QA can click through the actual change before merge.

It also makes review a shared act. A backend change that breaks a template shows up in the preview, not after release. A migration that fails on a fresh database fails in CI, where it is cheap to fix. Reviewers can test the flow on a phone, check a feature flag and confirm an error message without touching their laptop.

The cost is real: compute, databases, DNS and cleanup. Treat previews as a short-lived product, not a permanent copy of staging. Gate them behind a label or team membership when traffic or data risk is high. A preview that nobody owns becomes a zombie within a month.

Before you start

Write down the isolation boundary. A stateless web app can share a cluster and get a namespace per pull request. A service with a database needs its own schema, database or branch. A desktop or mobile app may only need a build artifact and a test report. The boundary decides how much you build and how you clean up.

Check the pieces you already have: a CI system that can run on pull request events, a container registry, a DNS zone you control, and a place to store secrets. You need a wildcard DNS record such as *.preview.example.com and a wildcard TLS certificate. Set those up before the first deploy or every preview will hit the same error. Decide who can open a preview: all pull requests, branches with a preview label, or members of a specific team.

Decide the data rule now. Never point a preview at production data. Use a small seed, fake records or an anonymized dump. If you need realistic volume, use a database branch or a restore from a sanitized snapshot, and give it a short lifetime. Write the rule in the repository so nobody has to remember it at 6 p.m. on a Friday.

How to do it

Start with one service and one environment type. Get a single pull request preview working end to end, including teardown, before you add a second service or a database. The steps below assume a containerized web app and a shared Kubernetes cluster. The same shape works on ECS, Fly.io machines or a platform with built-in preview builds.

Name everything from the pull request number. Use pr-482 as the namespace, the database schema, the hostname and the label. That one key makes cleanup a single query and stops two previews from colliding. Add labels for owner, created time and expiry so a scheduled job can find orphans.

Put the preview job behind a label such as preview or a comment command if you want control. Run it for same-repo pull requests. For fork pull requests, do not expose secrets. Either skip the deploy or use a workflow that requires a maintainer to apply a label first.

  1. Choose the isolation unit. Pick one namespace per pull request on a shared cluster, or one small stack per pull request if you need host-level isolation. Write the choice down, because it drives your cleanup and quota rules.
  2. Build one image per commit. Build a container image in CI and tag it with the commit SHA. Push it to your registry. Deploy that exact tag, not latest, so a preview maps to a known commit.
  3. Add pull request triggers. Create a CI job on opened, synchronize and reopened. Use a concurrency group keyed on the pull request number and cancel in-progress runs. Add a separate job on closed to tear down.
  4. Render the preview manifests. Keep a template for namespace, deployment, service, ingress and resource quota. Fill in the pull request number, image tag, hostname and expiry label with envsubst, Helm or your deploy tool. Apply it with a dedicated deploy role that can only touch preview resources.
  5. Create the database and seed it. Provision a schema or database named after the pull request, run migrations from scratch, then load a small seed. If your provider supports database branching, create a branch from a sanitized base and record its ID for teardown.
  6. Inject preview secrets. Store a staging-scoped set of credentials in your secret manager. Copy them into the preview namespace at deploy time. Do not reuse production secrets or long-lived cloud keys.
  7. Publish the URL on the pull request. Use wildcard DNS and ingress to route pr-482.preview.example.com to the service. Post the URL as a pull request comment and as a deployment status. Add a noindex header and an auth gate.
  8. Tear down on close and on a timer. Delete the namespace, database, ingress route and secrets when the pull request closes. Run a nightly job that deletes anything past its expiry label. Log what it removed so you can audit drift.

How to check it worked

Open two pull requests with the preview label at the same time. Change a visible string in each and confirm the two preview URLs show different content. Add a record in one preview and check it does not appear in the other. If both show the same data, you are sharing a database or a cache.

Push a second commit to one pull request. The preview should redeploy with the new image tag while the other pull request stays put. The pull request comment or deployment status should point at the new run. A stale preview usually means your concurrency group is not canceling old work or your ingress still points at the old service.

Close one pull request and watch the teardown job. The namespace should terminate, the database should disappear and the hostname should stop serving the old app and return a not found response from the ingress. Run the nightly cleanup in dry-run mode and confirm it lists only abandoned previews, not active ones. Open the URL in a private window and confirm the auth gate blocks you.

Mistakes to avoid

Pointing previews at a shared production database is the fastest way to leak customer records or corrupt real data. A preview should have its own schema or branch and fake seed data. Public preview URLs with no auth gate get crawled and shared. Add SSO, basic auth or an IP allowlist, and send noindex.

Previews that never expire turn into a second production system that nobody owns. Set an expiry label, run cleanup nightly, and make the deploy role unable to touch staging or production. Use resource quotas so one runaway preview cannot starve the cluster. Check the cleanup log weekly for patterns, such as a service that always leaks a load balancer.

Fork pull requests do not get repository secrets in most CI systems. Do not work around that by making secrets available to all pull requests. Use a label or a manual approval for outside contributors. Also cancel superseded runs, because two deploys for the same pull request can leave a service pointing at the wrong image. If you want the pipeline, secret handling and teardown built with your team, Cloudverg's Delivery platform setup, fixed at $14,500 over four weeks, is one option among others.

Frequently asked questions

What is a pull request preview environment?

It is a temporary deployment of the code in a pull request, reachable by its own address. It usually gets a unique namespace, database and hostname. It is deleted when the pull request closes or expires.

Do preview environments replace staging?

No. Staging checks integration across services and shared configuration. Previews check a single change in isolation. Keep both, but keep previews short-lived and cheap.

How do I stop preview environments from costing too much?

Set a short expiry, use resource quotas and tear down on pull request close. Share a cluster and use small database schemas or branches. Review orphaned resources monthly.

Fixed price

Want help with this? Delivery platform setup

$14,500 fixed price

4 weeks · Starts within 10 business days

Four weeks to give your engineers a delivery platform: pipelines, environments, secrets, monitoring and rollback they can trust.

What is included

Related guides

More devops and platforms guides   Engineering systems

Smallest way to start

Get a senior architect on your problem this week

Ninety minutes on the cloud, AI or security question that is blocking you, a pre-read of your material and a written summary within two business days.

$450 one-time