Vercel Ignored Build Step: script examples and pitfalls
The Ignored Build Step is a command Vercel runs before each Git build: exit code 0 skips the build, exit code 1 builds. Set it under Project → Settings → Git → Ignored Build Step, or as ignoreCommand in vercel.json.
Where to put it
In the dashboard pick Custom and paste the command. Or keep it in the repository:
{
"ignoreCommand": "bash scripts/vercel-ignore.sh"
}
The command runs in the project's root directory after the repository is cloned. A script file is easier to read and test than a long one-liner.
Examples
Only build production
bash -c '[ "$VERCEL_ENV" = production ] && exit 1 || exit 0'
Only build when this folder changed
git diff --quiet HEAD^ HEAD -- .
git diff --quiet exits 0 when nothing changed (skip) and 1 when something did (build), which is exactly what Vercel expects. Add shared folders after the dot, for example -- . ../../packages/ui.
Skip bot branches
bash -c 'case "$VERCEL_GIT_COMMIT_REF" in dependabot/*|renovate/*) exit 0;; *) exit 1;; esac'
Skip when the commit message says so
bash -c 'echo "$VERCEL_GIT_COMMIT_MESSAGE" | grep -qiF "[skip deploy]" && exit 0 || exit 1'
Only the newest commit of a push is checked.
Turborepo
npx turbo-ignore
A script that compares with the last deployment
HEAD^ only looks at the newest commit. If you push five commits, a change in the third is missed. This script compares with the commit of the last successful deployment instead, and builds whenever it cannot tell:
#!/usr/bin/env bash
# scripts/vercel-ignore.sh · exit 0 = skip the build, exit 1 = build
set -u
paths=(. ../../packages) # what this project depends on
prev="${VERCEL_GIT_PREVIOUS_SHA:-}"
[ -n "$prev" ] || exit 1 # first deployment: build
# Vercel clones shallow; fetch the old commit if it is missing
git cat-file -e "$prev^{commit}" 2>/dev/null || git fetch --depth=1 origin "$prev" 2>/dev/null || exit 1
git diff --quiet "$prev" HEAD -- "${paths[@]}" # 0 = no change = skip
Pitfalls
- The exit codes are the wrong way round compared with most CI tools. 0 means “ignore this build”. Test with
bash scripts/vercel-ignore.sh; echo $?. - Errors build. A typo, a missing tool or a failing
gitcommand exits non-zero, so Vercel builds. That is safe, but it makes a broken script look like it does nothing. HEAD^misses commits when one push has several. Compare withVERCEL_GIT_PREVIOUS_SHAas in the script above.- Shallow clone. Old commits may not be in the clone. Fetch them, or fall back to building.
- Empty variables.
VERCEL_GIT_PREVIOUS_SHAis empty on the first deployment of a branch. - It still costs a deployment. Vercel creates the deployment, clones, runs the check and cancels. The list fills with cancelled entries.
- Production too. A rule written for previews also applies to the production branch unless you check
VERCEL_ENV.
When a script is the wrong tool. If what you want is “deploy production when I decide”, a rule per project is a lot of upkeep. Turning auto-deploy off and deploying what changed with Deploy Center is one click for every project.
Questions
Does exit code 0 build or skip on Vercel?
Skip. Exit code 0 cancels the build, any other exit code (usually 1) lets it run.
Which environment variables can the ignore command use?
The system variables such as VERCEL_ENV, VERCEL_GIT_COMMIT_REF, VERCEL_GIT_COMMIT_SHA, VERCEL_GIT_COMMIT_MESSAGE and VERCEL_GIT_PREVIOUS_SHA, plus your project's environment variables.
Why does my build still run?
Most often the script exits non-zero because of an error, or HEAD^ only looked at the newest commit. Run the script locally and print the exit code.
Is a skipped build free?
It is cancelled before your build command runs, so it is much cheaper than a build. Check your usage page to see how your plan counts it.
Do it for every project in one click.
Deploy Center is a free, open-source Mac app. It turns off auto-deploy on Vercel, Render, Netlify, Cloudflare Pages and more, shows the commits and PRs waiting to go live, and deploys what changed when you decide.