Using Heroku Review Apps to Test Pull Requests Safely
Learn how Heroku Review Apps create disposable environments for each pull request, letting you test changes without affecting production, plus tips to control costs and clean up.
03 Jul 2025, 00:25 UTC

When a team relies on a single staging environment, testing a pull request can block others or risk introducing bugs into shared resources. Heroku Review Apps solve this by spinning up a temporary, isolated environment for every PR, letting you validate changes without affecting the main pipeline.
Problem: Shared environments create bottlenecks
In many CI setups, a single staging app is reused for all branches. If two developers open PRs at the same time, one test suite might overwrite data the other needs, or a long‑running test can tie up the staging dyno for hours. The result is delayed feedback and occasional “works on my machine” surprises when code finally merges.
Thesis: Review Apps give each PR its own disposable copy of the production‑like stack
Heroku Review Apps are created automatically from a pipeline whenever a pull request is opened. They inherit the pipeline’s codebase, add‑on configuration, and environment variables, but run in a separate dyno formation that is destroyed when the PR is closed or merged. This provides a clean slate for every change while keeping the workflow fully automated.
Setting up Review Apps
- Prerequisites: Heroku CLI installed, a Heroku account with permission to create pipelines and apps, and a GitHub repository connected to Heroku.
- Create a pipeline (if you don’t already have one):
heroku pipelines:create my-app-pipeline
- Add your existing Heroku app to the pipeline as the production stage:
heroku pipelines:add my-app-pipeline --app my-prod-app --stage production
- Add a
reviewapp.jsonmanifest to the root of your repo. This file tells Heroku how to build the review app (Docker image, add‑ons, config vars). Example:{ "image": "heroku/nodejs", "env": { "NODE_ENV": "test" }, "addons": ["heroku-postgresql:hobby-dev"] } - Enable automatic review apps in the pipeline settings (Dashboard → Pipelines → your pipeline → Settings → Review Apps) and set the GitHub connection.
After these steps, every new pull request triggers Heroku to:
- Build the slug using the same buildpacks as the parent app.
- Provision any add‑ons listed in
reviewapp.json(or inherit them from the pipeline). - Expose a unique URL like
https://pr-123-my-app.herokuapp.com.
Worked example: testing a new API endpoint
Suppose you open a PR that adds a /health endpoint to a Node.js service.
- Push the branch and open the PR on GitHub.
- Heroku detects the PR, creates a review app, and posts a comment with the generated URL.
- You run your test suite against that URL, for instance:
curl https://pr-123-my-app.herokuapp.com/health
Expected response:{"status":"ok"}. - If the tests pass, you merge the PR. Heroku automatically destroys the review app, freeing its dyno and add‑on resources.
To verify the cleanup, open the Heroku Dashboard → Usage → Dyno hours after the PR is closed. You should see the review app’s consumption drop back to baseline.
Trade‑off and limitation: resource usage and data persistence
Each review app consumes dyno hours and any add‑ons you provision (e.g., a Postgres hobby‑dev database). Heavy PR traffic can therefore increase your monthly bill or cause throttling if you exceed your plan’s limits. Moreover, because the app is torn down on close, any data written to add‑ons during testing is lost unless you reseed it via release scripts or fixtures.
Practical mitigation:
- Set a concurrency cap in the pipeline settings (e.g., max 5 simultaneous review apps) to bound costs.
- Configure an automatic expiration policy (e.g., delete after 12 hours of inactivity) so idle apps don’t linger.
- If tests need a known database state, include a seed script in the
releasephase of your app’sProcfileor use Heroku Postgrespg:copyto clone a fixture database on app start.
Actionable closing
Start small: enable review apps for a single low‑traffic pipeline, monitor the usage metrics for a week, and adjust the concurrency and expiration limits based on what you see. This gives your team fast, isolated feedback on every PR while keeping costs predictable and environments clean.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.