Skip to content
CodeAndBuild LogoCodeAndBuild

Git

Run a Next.js Typecheck and Build on Every Pull Request

Add a GitHub Actions workflow that installs dependencies, typechecks, and builds a Next.js app before a branch is merged.

CodeAndBuild Team8 min read
  • GitHub Actions
  • Next.js
  • CI
  • TypeScript
On this page
  1. Put the workflow in the repo
  2. Let the build see only public config
  3. Require the check before merge
  4. Read the first failing step

A pull request should fail in public when the project no longer typechecks or no longer builds. That check belongs in the repository, in a workflow file, so every branch runs the same steps on a clean machine. Your laptop already has node_modules, a warm cache, and a .env.local the CI runner will not have. The runner is the honest test.

Keep the first workflow boring. Check out the code, install from the lockfile, run the TypeScript compiler with no emit, then run the Next.js build. Add tests on the day you have tests. A workflow that tries to lint, test, scan, and deploy on the first afternoon usually fails for a reason nobody can see, and people start ignoring it.

Put the workflow in the repo

GitHub reads workflow files from .github/workflows. This one runs on pull requests and on pushes to main. The Node version should be the major version you deploy with. npm ci installs exactly the lockfile, which is what you want in CI. A plain npm install can quietly change versions.

.github/workflows/check.ymlyaml
name: check

on:
  pull_request:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm
      - run: npm ci
      - run: npx tsc --noEmit
      - run: npm run build

Let the build see only public config

next build will execute server code that reads environment variables at build time if your pages do that. Give CI the variables that are required to compile, and none of the production secrets. A site URL used for canonical links can be a repository variable. A database password and a mail API key should stay in production. If a page fetches private data during the build, change that page to fetch on request, or the check cannot pass on a clean runner.

  1. Run npm run build locally with .env.local renamed aside. Any crash you see there is the crash CI will see.
  2. Commit package-lock.json. npm ci refuses to run without it.
  3. Set the workflow Node version to the major version in production.
  4. Open a pull request that imports a missing type and confirm the check goes red.

Require the check before merge

A green workflow that nobody is required to wait for is a suggestion. In the repository settings, add a branch rule for main that requires the check job. Name it the way it appears on the pull request, which is the job name under the workflow name. After that, merge stays disabled until build has passed on the latest commit.

Cache the npm directory, which setup-node does when cache is npm, and leave Next.js build cache alone until the workflow is slow enough to care. A five-minute check on a small blog is a fair price. If install time dominates, the lockfile and the cache are the levers. If the build dominates, look at how much work the static generation does, not at a second CI provider.

Read the first failing step

When the run fails, open the log of the earliest red step. A type error belongs to tsc. A missing module, a bad import, or a page that threw during static generation belongs to the build. Fix that error in a new commit on the same branch. The workflow runs again. Avoid rerunning a failed job without a code change when the log already names the file.

More guides