Heroku Review Apps: Automating Pull Request Environments with app.json
Heroku Review Apps create temporary, isolated environments for each GitHub pull request. This guide covers the app.json setup, verification commands, and the dyno-hour and data-persistence limits that teams often miss.
05 Oct 2025, 04:49 UTC

The Problem: Shared Staging Slows Down Code Review
When every pull request deploys to the same staging server, reviewers test against a moving target. One developer's changes can overwrite another's, and configuration drift hides bugs that only appear in isolation. Heroku Review Apps address this by creating a disposable, full application instance for each open pull request, letting reviewers interact with the exact code under review without touching shared infrastructure.
The useful takeaway: if you already use Heroku Pipelines and GitHub, you can automate preview environments entirely through an app.json manifest and a dashboard setting. The trade-off is predictable cost in dyno hours and strict limits on data persistence.
How Review Apps Are Created
Heroku Review Apps rely on a declarative manifest called app.json placed at the root of your repository. This file tells Heroku what buildpacks to use, which add-ons to provision, how many dynos to run, and which environment variables are required. When a contributor opens a pull request against a branch connected to a Heroku Pipeline, Heroku reads the manifest, builds a new app, and attaches it to the PR as a clickable "Review app" link. When the pull request is closed or merged, Heroku destroys that app automatically.
This mechanism means the preview environment mirrors your production stack as closely as your manifest allows, but it remains ephemeral by design.
A Minimal app.json Example
The following manifest defines a single web dyno, a development-tier Postgres database, and one required secret. Place this file in your repository root and commit it before enabling Review Apps.
{
"name": "pr-preview",
"description": "Ephemeral preview for pull requests",
"formation": {
"web": {
"quantity": 1,
"size": "standard-1x"
}
},
"addons": [
"heroku-postgresql:mini"
],
"env": {
"SECRET_KEY_BASE": {
"description": "Used to sign sessions; set in pipeline settings or Heroku config",
"required": true
},
"APP_ENV": {
"value": "review"
}
},
"buildpacks": [
{
"url": "heroku/python"
}
]
}
In this example, formation pins the app to one standard-1x web dyno, which is the default tier for Review Apps. The addons array requests a Postgres database; note that Review Apps are generally restricted to lower-tier add-on plans, so verify that the plan you specify is available for review apps in your account. The env block declares SECRET_KEY_BASE as required, meaning the build will fail if the value is not supplied through the pipeline's configuration or Heroku's secure settings.
Enabling Review Apps in the Dashboard
Review Apps are a pipeline-level feature, not a per-app toggle. To activate them:
- Create or open a Heroku Pipeline and connect it to the GitHub repository containing your
app.json. - In the pipeline's Settings tab, locate the Review Apps section and enable Create Review Apps for the desired branch pattern (commonly
mainormaster). - Authorize the GitHub integration if prompted, then choose whether new review apps should be created automatically for every pull request or only when a maintainer requests one.
Once enabled, opening a new pull request triggers a build. You will see a status check in GitHub and a new entry under the pipeline's Review Apps tab.
Verifying the Configuration
After opening a test pull request, confirm that the review app matches your manifest. In the Heroku Dashboard, navigate to the pipeline and select the Review Apps tab. You should see the pull request number and a link to a dynamically generated subdomain.
For a deeper check, run the following command from your local terminal where the Heroku CLI is installed. You must have at least view permissions on the pipeline and the review app.
heroku apps:info -a <review-app-name>
Replace <review-app-name> with the actual name shown in the dashboard. Expected checks include:
- A
webdyno formation matching thequantityandsizeinapp.json. - Add-ons listed under the app's resources, confirming the Postgres attachment succeeded.
- The correct stack and buildpack applied.
This command is read-only and carries no risk of modifying the app.
Limits That Affect Cost and Behavior
Review Apps are convenient, but they consume the same underlying resources as regular apps. Understanding these boundaries prevents surprise invoices and broken workflows.
| Limit | Practical Impact |
|---|---|
| Dyno hours | Every running review app draws from your account's monthly dyno-hour quota. If you exceed the quota, Heroku may throttle or stop apps across the account. |
| Concurrent apps | A single pipeline is capped at 200 concurrent review apps. Most teams never approach this, but automated bot traffic can. |
| Add-on tiers | Review Apps are typically limited to development-tier add-ons. Production-grade Postgres or Redis plans are often unavailable. |
| Data persistence | Review Apps are destroyed when the PR closes. Any data written to the app's local filesystem or its dev-tier Postgres database is lost. Use external storage add-ons if persistence is required. |
| Workload profile | Review Apps share standard infrastructure limits. They are not suited for long-running background jobs or heavy load testing. |
Common Mistakes
Missing Required Config Vars
If app.json marks an environment variable as required but the value is not set in the pipeline's config or Heroku's secure settings, the review app build fails and the PR may not receive a deployment link. Always test a pull request yourself before announcing the feature to your team.
Assuming State Persists
Because the app is ephemeral, a review app's database resets on every new pull request. Do not use review apps to validate data migrations that depend on existing production rows, and do not store uploaded files on local disk expecting them to survive a rebuild.
Orphaned Apps from Broken Integration
Cleanup normally happens automatically when a pull request closes. However, if the GitHub integration loses authorization, the repository is transferred, or the pipeline is deleted, review apps may remain running. Periodically audit the Review Apps tab and delete any apps associated with closed pull requests.
A Practical Way to Check the Result
Before relying on Review Apps for daily work, run a controlled test:
- Open a pull request with a trivial change.
- Confirm the review app appears in the pipeline dashboard and the PR receives a deployment link.
- Run
heroku apps:info -a <review-app-name>to verify dyno and add-on configuration. - Check account usage via the Heroku Dashboard or
heroku invoicesto establish a baseline for dyno consumption. - Close the pull request and verify the app disappears from the Review Apps tab within a few minutes.
If the app persists after the PR is closed, investigate the GitHub integration permissions before opening additional pull requests. This baseline also helps you estimate how many concurrent reviews your dyno-hour budget can support.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.