Vercel Logo

Build Minutes

You fix a typo in the README. Push. Vercel builds the entire app, including the parts that have nothing to do with documentation. That build takes a minute and a half. You're billed for it.

Multiply by every README change, every comment fix, every CHANGELOG update across a year. On a fast-moving repo this is a few hundred unnecessary builds. Each one pays for a full reinstall, a full type check, a full bundle compilation, just to produce a deployment that is byte-identical to the one already running.

Vercel has an exit hatch. Before each build, Vercel runs whatever shell command you point it at. If that command exits 0, the build is skipped. If it exits 1, the build proceeds. We're going to point it at a tiny script that says "if only docs changed, skip."

What is the Ignored Build Step?

A project setting that runs a command of your choosing before every build. If the command exits 0, Vercel skips the build. If it exits 1, the build proceeds. It's the hook for "don't build when nothing that matters changed."

Outcome

Saturday has a working ignore-build-step.sh script in the repo root, and the project's Ignored Build Step setting is wired to run it. Doc-only commits skip the build.

Hands-on exercise 4.3

Three steps. One file, one file mode change, one dashboard toggle.

Requirements:

  1. Create ignore-build-step.sh at the root of the repo
  2. The script should compare the current commit against its parent and exit 0 if the only changed files are Markdown or live under docs/
  3. Run chmod +x ignore-build-step.sh so Vercel can execute it
  4. Open Saturday > Settings > Git
  5. Find the Ignored Build Step section
  6. Set the command to bash ignore-build-step.sh
  7. Commit the script, push, and test by making a docs-only commit

Implementation hints:

  • Exit code 0 means skip, exit code 1 means build. Get this backwards and your skip script will trigger builds and your build script will skip them. It is the most common mistake people make with this feature, and it's worth verifying twice.
  • The git diff --quiet HEAD^ HEAD -- ':!*.md' ':!docs/*' form is concise. --quiet returns 0 if there's no diff and 1 if there is. The :! syntax excludes paths from the diff. So if the only changes are inside excluded paths, --quiet returns 0 (no diff in the included set), and we exit 0 (skip the build).
  • The script runs from the project root with the deploying commit checked out. You don't need to cd anywhere.
  • Test with two commits: a code change and a docs change. The code one should produce a build, the docs one should be skipped.

Try It

After you've added the script and configured the setting, make a docs-only commit:

echo "## New section" >> README.md
git commit -am "docs: add new README section"
git push

Open the Deployments tab in Saturday. The new commit should appear with a status like:

docs: add new README section
Skipped (Ignored Build Step)

That's the success signal. No build minutes consumed, no new production deployment created, the existing one stays live.

Now make a code change:

echo "// trivial comment" >> app/page.tsx
git commit -am "chore: trivial comment"
git push

The deployment should proceed normally:

chore: trivial comment
Building...  Ready

Build minutes consumed, new production deployment created.

If both behaviors hold, the script is doing its job.

Done-When

  • ignore-build-step.sh exists at the repo root
  • The script is executable (ls -l ignore-build-step.sh shows the x bit)
  • Saturday > Settings > Git > Ignored Build Step is set to bash ignore-build-step.sh
  • A docs-only commit produces a "Skipped" status in Vercel
  • A code commit triggers a normal build

Troubleshooting

Every commit gets skipped.

The exit code logic is inverted. Your script is returning 0 when it should be returning 1, or the script is silently failing and bash is treating the failure as exit 0. Add set -e at the top of the script (which the solution version has) so silent failures don't pass.

Every commit triggers a build, even README-only ones.

The script isn't being executed, or the path check is wrong. Common causes: forgot chmod +x, the dashboard setting is set to the wrong path, the :! exclude syntax is interpreted differently in your environment. Try running the script locally on a docs-only diff: git diff --quiet HEAD^ HEAD -- ':!*.md' ':!docs/*' && echo "skip" || echo "build".

The first deploy with the script enabled triggered a "Skipped" status, but I wanted it to build.

The script compares against the parent commit. The commit that adds the script itself only touches ignore-build-step.sh, which isn't in the exclude list, so the script should exit 1 and build. If you're seeing skip, double-check the exclude patterns, your shell might be expanding :!*.md before git sees it. Quote the patterns: ':!*.md'.

Solution

The finished ignore-build-step.sh is on the complete branch if you want to check your version against it.

The script:

ignore-build-step.sh
#!/bin/bash
# Vercel Ignored Build Step script for Saturday.
# Configured under Project Settings > Git > Ignored Build Step.
#
# Exit 0 = skip build (proceed without deploying)
# Exit 1 = proceed with build
 
set -e
 
if git diff --quiet HEAD^ HEAD -- ':!*.md' ':!docs/*'; then
  echo "Only docs changed. Skipping build."
  exit 0
fi
 
echo "Code changes detected. Proceeding with build."
exit 1

And the dashboard configuration:

Settings > Git > Ignored Build Step
  Command: bash ignore-build-step.sh

You can get more elaborate. Monorepo users often check whether files under a specific app or package changed: git diff --quiet HEAD^ HEAD -- apps/saturday/ would skip when nothing in the Saturday app changed even if other things in the repo did. For a single-app repo, the docs-only check is the highest-leverage version.

Up next: the last cost lever. Sampling the observability tools so you keep the insights without paying for every event.

Was this helpful?

supported.