Open-Source Wikis

/

Next.js

/

How to contribute

/

Development workflow

vercel/next.js

Development workflow

The framework's iteration loop emphasizes watch builds and skipping isolation for the inner loop, with full builds reserved for branch switches and CI prep.

The inner loop

For changes to packages/next/src/:

# Terminal 1 — watch build (auto-rebuilds on change, ~1-2s per save)
pnpm --filter=next dev

# Terminal 2 — run a single test fast
NEXT_SKIP_ISOLATE=1 NEXT_TEST_MODE=dev pnpm testheadless test/e2e/app-dir/app/index.test.ts

NEXT_SKIP_ISOLATE=1 saves ~100s per test run by skipping the per-test packing of Next.js. Do not use it when validating module-resolution changes — the test will use the local dist/ directly and hide bugs that surface only when Next.js is packed as a real npm package. Drop the flag when:

  • Adding new require() paths
  • Adding new exports from entry-base.ts
  • Editing edge route imports
  • Validating fixes for previously-broken module resolution

NEXT_TEST_MODE=dev forces dev mode; use NEXT_TEST_MODE=start for production-mode tests.

When to do a full build

pnpm build-all    # full bootstrap
pnpm build        # JS only (after bootstrap)

Use pnpm build-all when:

  • Switching branches
  • Doing a fresh clone
  • Editing Rust code in crates/ or turbopack/
  • Before pushing for CI

Use pnpm --filter=next build when:

  • Edits are confined to packages/next/
  • You don't need Rust changes to take effect

For type errors only, pnpm --filter=next types is much faster (~10s vs ~60s) than a full build.

Branch hygiene

  • Branch off canary, not main. The canary branch is the active development branch and is what new releases are cut from.
  • Use a descriptive branch name. Common patterns: fix/..., feat/..., refactor/..., chore/....
  • Keep PRs focused on one change. The repo regularly rejects "kitchen sink" PRs because they slow review and bisecting.

Commit style

  • Concise, descriptive subjects. The squash-merge title becomes the squash-commit subject, so write the PR title like a commit subject.
  • No "Generated with Claude Code" or co-author footers.
  • Prefer present tense ("Fix X" not "Fixed X").

Splitting tasks

The repo's own contributor guide is explicit about decomposition: split work into small, independently verifiable steps and verify each before moving on. Concretely:

  1. Reproduce first — write a failing test before fixing.
  2. Make the smallest passing change — implement, run the failing test, see it pass.
  3. Add coverage — extend the test for adjacent edge cases.
  4. Lint and type-checkpnpm prettier --write <files> + npx eslint --config eslint.config.mjs --fix <files> + pnpm --filter=next types.
  5. Push and open PR as a draft.

For larger refactors, land an enabling PR (no behavior change) before the change-of-behavior PR.

Reading large files

Several files in this repo are >1,000 lines (app-render.tsx, base-server.ts, webpack-config.ts, build/index.ts). The advised pattern is:

  1. Grep for the symbol or string you care about with line numbers.
  2. Read targeted line ranges using offset/limit, not the whole file.
  3. Don't re-read the same range without a code change in between.

For generated files (packages/next/dist/, node_modules/, .next/), search rather than read.

CI cycle and reproducing failures

When CI fails:

node scripts/pr-status.js          # auto-detects PR from current branch
node scripts/pr-status.js <number> # specific PR

This script writes analysis files into scripts/pr-status/. The triage rules in priority order:

  1. Build failures — almost always real
  2. Lint failures — usually fixable with pnpm prettier-fix and pnpm lint-fix
  3. Type failures — pnpm types
  4. Test failures — verify locally before assuming flakiness

For local reproduction of a CI failure, mirror the CI environment variables. The most important ones:

CI env Effect
IS_WEBPACK_TEST=1 Forces webpack instead of Turbopack
NEXT_SKIP_ISOLATE=1 Skip packing Next.js (CI uses this for speed; module-resolution bugs may hide)
__NEXT_CACHE_COMPONENTS=true Enables cache components and PPR-by-default

CI workflow files at .github/workflows/build_and_test.yml show the exact env per job under afterBuild: blocks. Snapshot tests are env-sensitive — when updating snapshots, run with the same flags the failing CI job uses.

Pre-commit hook

The Husky hook at .husky/pre-commit runs lint-staged (configured in lint-staged.config.js) on the staged files. Each hit takes ~2 minutes. To pre-validate before committing:

pnpm prettier --with-node-modules --ignore-path .prettierignore --write <files>
npx eslint --config eslint.config.mjs --fix <files>

This runs exactly what the hook will run, so a successful pre-validate guarantees a fast commit.

Working against a real app

The scripts/next-with-deps.sh helper (exposed as pnpm next-with-deps) packs the local Next.js and links it into a target project. Use this when validating an end-to-end scenario that requires a real app shape rather than a test fixture.

For quick-start smoke tests:

pnpm new-test -- --args true smoke-feature e2e
node packages/next/dist/bin/next dev test/e2e/smoke-feature
curl --max-time 10 http://localhost:3000

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Development workflow – Next.js wiki | Factory