Migrate to RunxBuild and earn up to $50 in hosting credit on your first deposit.

Calculate your savings
unxBuild

Branch Deploy on Netlify: How It Works and When to Use One

Sean

Platform Writer

Sep 01, 2026
7 min read

A branch deploy publishes a non-production Git branch to its own persistent URL, so a staging or development branch has a stable address that updates on every commit rather than changing with each pull request.

Branch Deploy on Netlify: How It Works and When to Use One

The word that does the work is persistent. That is the whole distinction from a deploy preview, which most people conflate with it, and it is the reason to use one: a stable staging address you can share with a client, point a test suite at, or configure as a callback in a third-party service.

This covers the mechanics, the difference from previews, and the two things that catch people out, which are environment variables and unintended public access.

Table of contents

Branch deploys versus deploy previews

Three deploy types exist and they are triggered by different events.

A production deploy comes from a commit to your production branch and serves your main domain.

A branch deploy comes from a commit to a branch you have configured for deployment. It publishes to a URL that includes the branch name, and that URL is stable: every commit to the branch updates the same address.

A deploy preview comes from a pull request. It gets an ephemeral URL tied to the pull request number, and it disappears when the request is merged or closed.

The URL pattern makes the distinction concrete. A branch deploy publishes to a branch-prefixed subdomain, joined with two hyphens, so a branch called staging lands at staging--yoursite.netlify.app. A preview uses the pull request number instead.

The rule of thumb: previews for reviewing a change, branch deploys for an environment that persists. A pull request preview is for one conversation; a staging branch is for a standing address you configure other things against.

Turning them on

Branch deploys are off by default and require a Developer or Owner to enable them, which is a sensible default because every deployed branch is a build and a publicly reachable site.

In the site’s build and deploy settings you choose between deploying all branches or naming specific ones. Naming specific branches is almost always the right call: deploying all of them means every experimental branch someone pushes becomes a live public site and consumes build minutes.

For a typical project the list is short. A staging branch, perhaps a develop branch, and nothing else.

The build command and publish directory are shared with production by default. If a branch needs different build behaviour, use a context block in your configuration:

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

[context.staging]
  command = "npm run build:staging"

[context.branch-deploy]
  command = "npm run build:preview"

[context.deploy-preview]
  command = "npm run build:preview"

The branch-deploy context applies to every branch deploy that does not have a more specific context, and a named context like staging takes precedence over it. That precedence is worth remembering, because it is how you give one branch different behaviour from the rest.

Environment variables per context

This is the part that produces the most confusing bugs, and the failure is always the same shape: staging writes to production.

By default, environment variables apply to every deploy context. So your production database URL, your live payment key and your production analytics identifier are all present in the staging build unless you scope them.

Scope them explicitly in the dashboard, where each variable can be set to different values per context, or leave a variable undefined in a context so the build fails loudly rather than silently using production.

Failing loudly is genuinely the better default here. A staging build that crashes because DATABASE_URL is missing is a five-minute fix. A staging build that succeeds against the production database is a data incident that may not surface for days.

Two specific things worth checking on any branch deploy before you share the URL: which database it talks to, and whether it can send email. Those are the two that do real damage when they point at production.

Keeping branch deploys out of search results and out of public view

A branch deploy is a live, publicly reachable website with its own address. That means it can be crawled and indexed, and staging content appearing in search results is a genuinely common embarrassment.

Two protections, and you want both.

First, password-protect all branch deploys. This is a site-level setting that applies to every non-production deploy, and it is the strongest option because it does not depend on a crawler respecting anything.

Second, serve a noindex header on non-production contexts. Add it conditionally in your build:

# In _headers, or generated per context at build time.
/*
  X-Robots-Tag: noindex, nofollow

Generate that file only when the deploy context is not production, so it never reaches your live site. A _headers file with a global noindex accidentally shipped to production is a memorable way to lose your search traffic.

Also consider branch subdomains if you use the platform’s DNS. Instead of the default branch-prefixed address, a branch can serve from staging.yourdomain.com, which is nicer to share and easier to configure as an allowed callback in third-party services.

Whether branch deploys are the environment model you want

The strength of this approach is that environments are cheap and automatic. You get a live URL per branch without provisioning anything, which is genuinely excellent for a static site or a frontend against an existing API.

The limitation is that only the frontend is branched. Your database, your backend services and your background workers are not. So a staging frontend either points at production data, which is dangerous, or at a separately maintained staging backend, which is a manual environment you now own and which drifts.

For a full-stack application, environment parity matters more than URL convenience. What you want is the ability to run the same shape of stack, a service plus a database plus storage, more than once, with the smaller copy costing less rather than requiring different infrastructure.

On RunxBuild a staging environment is the same objects as production on smaller plans: a service deployed from a branch, its own managed Postgres or MySQL, its own environment variables and its own domain. The static sites documentation covers the frontend half, and the database sits beside it rather than being shared with production by default.

How this fits the rest of the stack

Staging is one of those costs that is easy to leave out of a plan and then pay for in incidents, and the useful question is what a second, smaller copy of the stack actually costs. The RunxBuild hosting calculator makes that concrete: a Dev plan at $4 alongside a small database is usually a much smaller number than teams expect, and considerably smaller than one afternoon spent recovering from a staging build that wrote to production.

Useful related references:

FAQ

What is the difference between a branch deploy and a deploy preview?

A branch deploy is triggered by commits to a configured branch and publishes to a stable URL that updates with each commit. A deploy preview is triggered by a pull request, gets an ephemeral URL tied to that request, and disappears when it is merged or closed. Use previews for review and branch deploys for persistent environments.

What URL does a branch deploy get?

The branch name, two hyphens, then your site name on the platform domain. A branch called staging publishes to staging—yoursite.netlify.app. If you use the platform’s DNS you can enable branch subdomains instead, giving the branch an address like staging.yourdomain.com.

Are branch deploys publicly accessible?

Yes by default, and they can be crawled and indexed. Enable password protection for all branch deploys, and serve a noindex header on non-production contexts. Generate that header only outside production, since shipping a global noindex to your live site removes it from search results.

Do branch deploys use the same environment variables as production?

By default yes, which is the most common source of trouble. Scope variables per deploy context so staging does not receive production credentials. Leaving a variable undefined in a context is often better than setting a fallback, because a failed build is a much smaller problem than a staging build writing to production.

Should I enable branch deploys for all branches?

Usually not. Deploying every branch means each experimental push becomes a live public site and consumes build minutes. Name the specific branches that need a persistent environment, typically just staging or develop, and rely on pull request previews for everything else.

#branch deploy netlify#netlify#deploy preview#staging environment#continuous deployment