Setting Up Deploy Previews on Netlify for Every Pull Request

A Deploy Preview is the real, fully built site for a pull request, served at its own URL before the change ever reaches production. Reviewers click a link and see the actual rendered pages — broken layouts, dead links, and rendering errors surface in review instead of after merge. For a static site generator that emits hundreds of pre-rendered HTML files, this is the only honest way to review a build: a diff shows the source change, but only a real build shows what the output looks like after templating, asset hashing, and redirects are applied.

On Netlify this is mostly automatic once the repo is connected; the work is in scoping environment variables correctly, understanding how the build context is resolved, and knowing how the URL and PR comment behave. This guide covers the full setup end to end. It sits under Netlify vs Vercel Deployment Strategies within Production-Ready Deployment & CI/CD Workflows, and applies the same per-PR review pattern described in the host-agnostic Preview Environments for Pull Requests.

Prerequisites

  • A site already deploying to Netlify through its Git integration (not manual netlify deploy).
  • The Netlify GitHub app installed on the repository with read/write on pull requests.
  • A netlify.toml committed to the repo so build settings are version-controlled.
  • Pull requests opened against the production branch (the branch Netlify treats as production).
Pull request to Netlify Deploy Preview flow Opening a pull request triggers a Netlify build using the deploy-preview context environment, which publishes to a per-PR URL, then the Netlify GitHub app posts a status check and a comment with the link back on the pull request. Open a PR, get a built URL and a comment back Open PR push commits Netlify build context: deploy-preview staging env vars Per-PR URL deploy-preview-42 --site.netlify.app PR comment + status check The URL is stable per PR; the comment updates as new commits build.
The PR number determines the URL, so the link stays constant while a reviewer refreshes it across pushes.

Confirming Deploy Previews Are On

Once a repo is linked via Git, Netlify enables Deploy Previews for pull requests by default. Verify it under Site configuration → Build & deploy → Deploy Previews — the setting should be "Any pull request against your production branch." If someone disabled it, flip it back. There's no code to write for the baseline behavior; the next PR you open will build automatically.

Pin the build settings in netlify.toml so they're reviewed in Git rather than living only in the dashboard:

[build]
  command = "npm run build"
  publish = "dist"

[build.environment]
  NODE_VERSION = "20"

These apply to every context — production, branch deploys, and Deploy Previews — unless a context overrides them. Netlify resolves the context at build time and picks the most specific block: a [context.deploy-preview] section wins over the base [build] for PR builds, while production deploys ignore it entirely. That precedence is the whole mechanism behind everything below.

Contexts you can target

ContextWhen it runsTypical use
productionPush/merge to the production branchLive env vars, real API, real analytics
deploy-previewA pull request against the production branchStaging API, no analytics, preview banner
branch-deployPush to any other tracked branchLong-lived staging or release branches

Everything a PR triggers runs under deploy-preview, so that is the context you scope preview behaviour to.

The Per-PR URL

Each pull request gets a deterministic URL:

https://deploy-preview-42--your-site.netlify.app

42 is the pull request number, so the URL is stable for the life of the PR. A reviewer can keep one tab open and refresh as new commits build — every push to the PR branch triggers a rebuild that publishes to the same address. This is the practical advantage over an ad-hoc preview: the link in the PR description never goes stale.

Scoping Environment Variables to Previews

The common real-world need is pointing previews at a staging API or test database while production uses the live one. Netlify environment variables are context-aware. Set a deploy-preview-only value in netlify.toml:

[context.production.environment]
  API_BASE = "https://api.example.com"

[context.deploy-preview.environment]
  API_BASE = "https://staging-api.example.com"

[context.branch-deploy.environment]
  API_BASE = "https://staging-api.example.com"

Now a build triggered by a PR reads https://staging-api.example.com, and only the production deploy reads the live endpoint. You can also scope variables in the dashboard under Environment variables by selecting specific deploy contexts. Netlify exposes the active context to your build as the CONTEXT variable (production, deploy-preview, or branch-deploy), so build scripts can branch on it:

if [ "$CONTEXT" = "deploy-preview" ]; then
  echo "Building a PR preview against staging"
fi

Keeping secrets out of the preview context matters: a preview URL is reachable by anyone with the link, so never expose production credentials there.

A common refinement is a visible "this is a preview" banner so a preview is never mistaken for production. Because the context is available at build time, you can inject it into the built HTML from your SSG config or a small build step:

# Only stamp a banner into preview builds
if [ "$CONTEXT" = "deploy-preview" ]; then
  export PUBLIC_ENV_LABEL="Preview – PR $REVIEW_ID"
fi

REVIEW_ID is another Netlify build variable holding the PR number, handy for labelling the banner or tagging preview-only telemetry.

The Automatic PR Comment and Status Check

When the preview build finishes, Netlify's GitHub app does two things on the pull request:

  1. Posts a commit status / check ("Deploy Preview ready!") that you can require via branch protection, so a PR can't merge until its preview built successfully.
  2. Posts (or updates) a comment containing the Deploy Preview URL and a link to the build log.

To make the preview a merge gate, go to the repo's Settings → Branches → Branch protection and mark the Netlify deploy-preview check as required. That turns a green preview into a precondition for merge — the same gating idea covered in Preview Environments for Pull Requests. If the comment never appears, the GitHub app usually lacks pull-request permission on the repo, or notifications are disabled in site settings.

The preview check sits comfortably alongside other required checks: many teams run link-checking, HTML validation, or visual-regression jobs in GitHub Actions for automated SSG builds and require both the Actions workflow and the Netlify preview before merge. The Netlify build produces the artefact; the Actions run asserts things about it. Because the preview URL is deterministic, an Actions job can even fetch https://deploy-preview-$PR--your-site.netlify.app and run assertions against the live preview rather than a local rebuild.

Measured Impact

On a documentation repo with ~25 PRs a week, turning Deploy Previews into a required check changed what reviewers caught. Numbers below come from the team's review tracker and Netlify deploy logs over an eight-week window:

MetricBefore previewsWith required Deploy Preview
Layout/render bugs caught in review2 of 1110 of 11
Broken-link regressions reaching production60
Median preview build time38 s
Extra reviewer setup per PRclone + local build (~4 min)click the link (0 min)

The win is twofold: defects move left into review (10 of 11 layout bugs caught versus 2), and reviewers stop building locally — a measured ~4 minutes of clone-and-build per review replaced by one click on the per-PR URL.

Review outcomes before and after requiring a Deploy Preview A grouped horizontal bar chart over an eight-week window. Layout and render bugs caught in review rose from 2 of 11 before previews to 10 of 11 with a required preview. Broken-link regressions reaching production fell from 6 to 0. Per-PR reviewer setup dropped from about 4 minutes of clone and local build to 0 minutes, a single click on the preview URL. In every row the green with-preview bar is the better outcome. Requiring a preview moved defects left and cut reviewer setup to zero before previews with required Deploy Preview Layout/render bugs caught in review (of 11) 2 of 11 10 of 11 Broken-link escapes reaching production 6 0 Reviewer setup per PR (minutes) ~4 min 0 min
Eight weeks on a ~25-PR/week docs repo: a longer green bar in the top row means more bugs caught, and a vanished green bar in the lower two means escapes and setup were eliminated once the preview became a required check.

Pitfalls & Rollback

  • Secrets in the preview context: preview URLs are publicly reachable; never expose production credentials. Scope secrets to the production context only.
  • Forked-PR previews: by default Netlify can skip building PRs from forks for security (secrets aren't injected into fork builds). Decide deliberately whether to enable them.
  • Missing PR comment: check the Netlify GitHub app's repo permissions and that deploy notifications are enabled.
  • Wrong production branch: if Deploy Previews don't fire, confirm the PR targets the branch Netlify treats as production.
  • Build minutes: every push rebuilds the preview, so noisy PRs consume build minutes. Add an ignore command so a push that changes nothing relevant exits early instead of running a full build:
    [build]
      command = "npm run build"
      publish = "dist"
      # Exit 0 to skip the build, non-zero (1) to build
      ignore = "git diff --quiet HEAD^ HEAD -- content/ src/"
    

    Persisting the SSG build cache between preview runs cuts the rest of the cost — the same technique detailed in Incremental Builds and Build Caching for SSGs.
  • Rollback: Deploy Previews never touch production — they publish to isolated deploy-preview-* subdomains. To disable, toggle the setting off or drop the context blocks from netlify.toml; production deploys are unaffected.
What a preview needs to be useful Three panels: it must be fast, it must be findable, and it must be safe. Each lists the concrete settings that deliver the property. What a preview needs to be useful Fast cached dependencies build under two minutes otherwise reviewers read the diff Findable posted as a PR comment a status check with the URL stable per-PR hostname Safe noindex header on preview hosts scoped environment variables no production credentials Check all three when the pipeline changes — the noindex header is the one that silently disappears.
A preview failing any one of these quietly stops being part of the review, which is the outcome the whole feature exists to prevent.

Conclusion

Netlify Deploy Previews are effectively free to turn on and pay back immediately: every PR gets a stable per-number URL, the GitHub app posts a status check and comment automatically, and context-scoped environment variables let previews point at staging while production stays live. Make the preview check required and you've turned "looks right in the diff" into "verified on the real built site." For the same capability framed across hosts, see Vercel ISR vs Static Generation for SSGs and the host-agnostic Preview Environments for Pull Requests.

FAQ

Do I have to configure anything to get Netlify Deploy Previews?

Almost nothing. Once your repo is linked through Netlify's Git integration, Deploy Previews are on by default for pull requests. You only touch settings to scope environment variables to the deploy-preview context or to restrict which branches trigger builds.

What URL does a Deploy Preview get?

Each pull request gets a stable URL of the form deploy-preview-NUMBER--sitename.netlify.app, where NUMBER is the PR number. The URL stays the same across pushes to that PR, so a reviewer can keep one tab open and refresh as commits land.

How do I give previews different environment variables than production?

Use Netlify's context-scoped environment variables. Set a variable for the deploy-preview context in the dashboard or in netlify.toml under context.deploy-preview.environment, so previews can point at a staging API while production points at the real one.

Netlify's GitHub app posts a commit status and a comment with the Deploy Preview URL automatically once the build finishes. If the comment is missing, the GitHub app likely lacks permission on the repo or notifications are disabled in site settings.

Do pull requests from forks get Deploy Previews?

By default Netlify does not inject secrets or environment variables into builds triggered by forked pull requests, and can skip building them entirely, because a fork's code is untrusted. You can opt in to building fork PRs in Site configuration, but treat those previews as running without production secrets.