Copy link to headingHow to run a different Vercel build command per environment or branch
Vercel runs one build command per deployment, but that command doesn't have to be the same everywhere. Point it at a script that reads the deployment's environment or branch. A single project can then run npm run build:production for production and npm run build:preview for every preview.
Here's how Vercel decides which command to run, and how to make that decision depend on the environment, the Git branch, or your own environment variables.
Copy link to headingHow Vercel resolves your build command
Three places can set the build command, and each one overrides the ones below it:
vercel.jsonorvercel.ts: AbuildCommandproperty applies to deployments built from that commit, so it can differ per branch.- Project Settings: The Override toggle under Settings > Build and Deployment applies to every deployment in the project.
- The framework preset: Vercel picks a default based on the framework you're deploying.
If Next.js is your framework, Vercel looks for a build script in scripts and runs it, and falls back to next build if there isn't one. So npm run build ends up being the effective command even though nothing on Vercel names it.
A dynamic build command is a deliberate use of the top two layers. You override the default with a command that runs a script, and the script decides the rest.
Copy link to headingHow to run different build commands per environment
Start with the two npm scripts your build will choose between, defined in package.json:
Next, create a vercel.sh file in your project's root directory that branches on the environment.
Use VERCEL_ENV, which is set to production, preview, or development on every deployment:
The script can be written in Bash or Node.js, and it has access to every system environment variable Vercel exposes at build time.
If your project uses custom environments such as staging or QA, VERCEL_ENV reports those as preview. Read VERCEL_TARGET_ENV instead, which returns production, preview, development, or the name of the custom environment.
Finally, point the build command at the script. You can do this in your project configuration file or in the dashboard.
Set buildCommand in vercel.json:
To do the same in the dashboard, select your project and open Settings > Build and Deployment. Turn on the Override toggle for Build Command and enter sh vercel.sh.
Both routes run the same script. Pick vercel.json when the command should differ per branch, and the dashboard when it shouldn't.
Copy link to headingHow to set a per-branch build command on Vercel
Matching on the branch name varies the build per branch, without configuring a custom environment for each one.
Read VERCEL_GIT_COMMIT_REF, which holds the Git branch of the commit that triggered the deployment:
Use VERCEL_GIT_COMMIT_REF rather than VERCEL_BRANCH_URL for this. VERCEL_BRANCH_URL holds the generated branch domain, such as my-site-git-improve-about-page.vercel.app, so matching on it means parsing a hostname instead of comparing a branch name.
Copy link to headingEnvironment and branch settings in the dashboard
Matching on VERCEL_TARGET_ENV depends on the dashboard configuration. A branch only reports a custom environment's name if that environment tracks it, so open Settings > Environments, select the environment, and set the branch under Branch Tracking. Without that, the branch deploys as a preview and your script takes the preview path.
Copy link to headingBuild command recipes for monorepos and generated config
Three setups need more than an environment or branch check:
- Switch on your own variable: Add a variable such as
BUILD_PROFILEin Settings > Environment Variables, scope it per environment or per branch, and branch on it invercel.sh. The script then stays stable while the routing lives in the project configuration. - Give each monorepo app its own command: Connect each app as a separate Vercel project, set its Root Directory under Settings > Build and Deployment, and give that project its own build command. Each project builds independently from the same repository.
- Compute the configuration itself: Use
vercel.tsinstead ofvercel.json. It executes at build time rather than being static, so the configuration can be generated rather than hardcoded.
A vercel.ts file exports a typed config object and accepts the same property names as vercel.json:
Use one configuration file or the other. A project should have vercel.ts or vercel.json, not both.
Copy link to headingWhen to skip a build instead of changing the build command
Some cases don't call for a different command at all. To stop a commit from building, use the Ignored Build Step rather than exiting early from vercel.sh. A build command that exits cleanly still produces a deployment, while the Ignored Build Step cancels it.
The Ignored Build Step runs a command of your choosing when the deployment enters the BUILDING state. It runs from the project's Root Directory and has access to system environment variables. An exit code of 1 continues the build, and an exit code of 0 cancels it and sets the deployment state to CANCELED.
Set it under Settings > Build and Deployment, or override it per deployment with ignoreCommand in vercel.json or vercel.ts.
Canceled builds still count as full deployments against your deployment quota and concurrent build slots. For the script patterns and monorepo examples, see the Ignored Build Step guide.
Copy link to headingHow to troubleshoot a Vercel build command that isn't running
When the script doesn't take effect, the cause is usually configuration rather than the script itself:
- Permission denied when the script runs: Set the build command to
shvercel.shrather than./vercel.sh. Running the file throughshmeans its executable bit doesn't need to be committed to Git. - The old command still runs: Build and Deployment settings apply from the next deployment onward. Open the Deployments tab and select Redeploy to pick up the change.
- Every deployment takes the
elsebranch: Your script is reading an empty variable. Open Settings > Environment Variables and select Enable access to System Environment Variables, which exposesVERCEL_ENVandVERCEL_GIT_COMMIT_REFto the build. - The script isn't found in a monorepo: A build can't reach files outside its Root Directory. Move
vercel.shinside that directory rather than leaving it at the repository root. - Your settings are ignored entirely: A
buildsarray invercel.jsonmakes Vercel ignore your Build and Deployment settings. Removebuildsand use thefunctionsproperty instead.
If the script runs but takes the wrong branch, echo the variable you're matching on and read the value back in your build logs.
Copy link to headingNext steps
With the build command routing correctly, the same repository can serve preview and production builds from one project. Start a new Vercel project to set this up from the beginning, or browse the templates for a framework-ready starting point.
Copy link to headingRelated resources
- Configuring a build
- Static configuration with vercel.json
- Programmatic configuration with vercel.ts
- System environment variables
- How do I use the "Ignored Build Step" field on Vercel?
- Using monorepos
Copy link to headingFrequently asked questions
Copy link to headingWhat is the difference between the build command and the framework preset?
The framework preset tells Vercel which framework you're deploying and supplies defaults for the build command, output directory, and install command. The build command is one of those defaults. Changing the preset changes several settings at once, while overriding the build command changes only what Vercel runs to build your project.
Copy link to headingCan I override the Vercel build command for a single deployment?
Yes. Add buildCommand to vercel.json or vercel.ts on the branch you're deploying, and it takes precedence over the Build Command in Project Settings. Because the file is versioned alongside your code, each branch can carry its own configuration without any dashboard change.
Copy link to headingWhich environment variable tells my script which branch is building?
Match on VERCEL_GIT_COMMIT_REF, which carries the branch name and is available at both build and runtime. For the environment rather than the branch, use VERCEL_ENV for production, preview, or development, or VERCEL_TARGET_ENV when you need the name of a custom environment, such as staging.
Copy link to headingCan I test my build command locally before deploying?
Run vercel pull to fetch your Project Settings and environment variables, then vercel build to run the same build command Vercel would. Add --target=staging to build against a specific environment, or --prod to use Production environment variables instead of the Preview defaults.