Open-Source Wikis

/

Next.js

/

Reference

/

Dependencies

vercel/next.js

Dependencies

The framework's dependency story is unusual: the runtime ships 141 vendored packages (compiled into a single distribution), and the user-visible dependencies block in packages/next/package.json is intentionally tiny.

Vendored packages

packages/next/src/compiled/ contains 141 third-party packages bundled into the framework. Each is built into a single file (or small set of files) via @vercel/ncc with the recipes in taskfile.js.

Why vendor:

  • Lock the runtime to a specific version, immune to user node_modules resolution.
  • Avoid pulling many tiny packages into user node_modules.
  • Ship the framework as a single self-contained artifact.

Major vendored packages:

Package(s) Role
react, react-dom (+ canary, experimental) The bundled React the framework ships
react-server-dom-webpack, react-server-dom-turbopack (+ experimental) RSC over webpack and Turbopack
webpack The webpack bundler
acorn JS parser for static analysis
babel, @babel/* The babel toolchain (still used in places)
@edge-runtime/* Edge runtime sandbox
@vercel/nft Node File Tracer
@vercel/og OG image generation
@modelcontextprotocol/sdk MCP SDK for IDE integration
@mswjs/interceptors Test-mode HTTP interceptors
terser, cssnano-simple Minifiers
zod, zod-validation-error Config schema validation
busboy Multipart form parsing for server actions
path-to-regexp Route pattern matching
picomatch Glob matching
comment-json JSON-with-comments for tsconfig.json
jest-worker Worker pool primitive
tar Tarball extraction (codemods, examples)
ua-parser-js User-agent parsing
watchpack File watching
100+ more Browserify polyfills, http helpers, css-loader, etc.

Real (non-vendored) dependencies

The user-installed dependencies in packages/next/package.json:

"dependencies": {
  "@next/env": "16.3.0-canary.5",
  "@swc/helpers": "0.5.15",
  "baseline-browser-mapping": "^2.9.19",
  "caniuse-lite": "^1.0.30001579",
  "postcss": "8.5.10",
  "styled-jsx": "5.1.6"
}

Six packages. The reasoning per package:

  • @next/env — separate so it can be loaded standalone (used by user code that wants .env parsing without the full framework).
  • @swc/helpers — runtime helpers for SWC-compiled code; can't be vendored because user bundles need to resolve them too.
  • baseline-browser-mapping, caniuse-lite — large datasets, refresh frequently, easier as deps.
  • postcss — stays user-resolvable so user PostCSS plugins can hook in.
  • styled-jsx — transitive runtime dep. User code can import 'styled-jsx' directly.

Optional dependency

"optionalDependencies": {
  "sharp": "^0.34.5"
}

sharp is the native image-resizing library used by the image optimizer. Optional because it has prebuilt binaries for many platforms but not all; on platforms without sharp the optimizer falls back to a wasm path.

Peer dependencies

"peerDependencies": {
  "@opentelemetry/api": "^1.1.0",
  "@playwright/test": "^1.51.1",
  "babel-plugin-react-compiler": "*",
  "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
  "react-dom": "...",
  "sass": "^1.3.0"
}

react and react-dom are peer dependencies even though the framework vendors copies of them. The vendored copy is only used internally; user code resolves their own copy. Both must be compatible.

@playwright/test is the framework's experimental test-mode integration.

babel-plugin-react-compiler is the React Compiler, optional.

@opentelemetry/api enables the framework's OTel spans when the user installs it.

sass enables .scss files when the user installs it.

Root devDependencies

The repo's root package.json lists devDependencies for the workspace itself: jest, prettier, typescript, eslint, playwright, tsx, lerna, turbo, etc. These are repo tooling, not shipped to users.

A few of note:

  • turbo: 2.9.4 — the Turborepo build orchestrator (different from Turbopack).
  • lerna: 9.0.3 — package management.
  • pnpm: 10.33.0 (in packageManager) — package manager.
  • typescript: 6.0.2 — typecheck the workspace.

Patches

Several upstream packages have patches applied via pnpm's patch mechanism:

"patchedDependencies": {
  "webpack-sources@3.2.3": "patches/webpack-sources@3.2.3.patch",
  "stacktrace-parser@0.1.10": "patches/stacktrace-parser@0.1.10.patch",
  "@types/node@20.17.6": "patches/@types__node@20.17.6.patch",
  "taskr@1.1.0": "patches/taskr@1.1.0.patch",
  "minizlib@3.1.0": "patches/minizlib@3.1.0.patch",
  "http-proxy@1.18.1": "patches/http-proxy@1.18.1.patch",
  "web-vitals@4.2.1": "patches/web-vitals@4.2.1.patch",
  "@rspack/core@1.6.7": "patches/@rspack__core@1.6.7.patch",
  "@modelcontextprotocol/sdk": "patches/@modelcontextprotocol__sdk.patch",
  "@vercel/blob": "patches/@vercel__blob.patch",
  "postcss-scss": "patches/postcss-scss.patch"
}

Each patch lives in patches/. Reasons vary (upstream bug fixes pending merge, monkey-patch behavior change). When upstream merges, drop the patch.

Vendoring workflow

To update a vendored package:

  1. Edit the version under packages/next/package.json devDependencies.
  2. Run pnpm install.
  3. Re-run the vendoring task (pnpm runs ncc as part of the build).
  4. Diff the output under packages/next/src/compiled/ and commit.

Some vendored packages have build scripts in packages/next/taskfile.js that customize what gets bundled (e.g., excluding test files, applying additional transforms).

React vendoring

React occupies a special place. The framework vendors:

  • react, react-dom, react-is (canary release pinned via the react dep alias)
  • react-experimental, react-dom-experimental (separate folder, experimental release)
  • react-server-dom-webpack, react-server-dom-turbopack (RSC bridges, both stable + experimental)
  • scheduler, scheduler-experimental

The exact pinned versions live in the repo's root package.json under pnpm.overrides:

"react": "npm:react@19.3.0-canary-da9325b5-20260417",
"react-dom": "npm:react-dom@19.3.0-canary-da9325b5-20260417",
"scheduler": "npm:scheduler@0.28.0-canary-da9325b5-20260417"

Updates use pnpm sync-react (which calls scripts/sync-react.js) to fetch the latest canary build and update all references.

Why so much vendoring?

Two main reasons:

  1. Reproducible runtime: regardless of what user code installs, the framework's behavior depends only on what the framework ships.
  2. Smaller user node_modules: a single next package replaces what would otherwise be 100+ packages.

Key paths

Path What
packages/next/src/compiled/ All vendored packages
packages/next/package.json Real deps + devDeps
packages/next/taskfile.js Vendoring recipes
package.json (root) Workspace + pnpm overrides
patches/ Patches applied via pnpm
scripts/sync-react.js React-version sync
scripts/install-native.mjs postinstall: pick platform @next/swc-{platform}

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

Dependencies – Next.js wiki | Factory