# Extension points — vercel/next.js

> Canonical page: https://codevetter.com/unpack/nextjs/extension-points

# Extension points — vercel/next.js

Scanned commit 2861a364fcbe75fe96b0b9127f9b335edfcf288c (2026-09-22). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

Next.js is built to be extended at five distinct seams: the CLI command table, the config schema + `define-env` pipeline for feature flags, the `RouteModule` class hierarchy for new route kinds, the `CacheHandler` / adapter interfaces for hosting and storage backends, and the test-harness registries (`@gate` conditions, bundler manifests). The repo also formalises extension of the *agent* workflow itself through `.agents/skills/`, with a meta-skill for authoring new ones.
- New CLI subcommands plug into the Commander table in `bin/next.ts` — add a `.command(name)` + `.action(() => import('../cli/next-<name>.js'))` pair and a matching `Next<Name>Options` type; the `internal` sub-group shows the pattern for hidden/maintenance commands. — [packages/next/src/bin/next.ts#L187-L200](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/packages/next/src/bin/next.ts#L187-L200) [packages/next/src/bin/next.ts#L665-L700](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/packages/next/src/bin/next.ts#L665-L700) [packages/next/src/cli/](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/packages/next/src/cli/)
- A new feature flag is a four-file change by convention: the type in `server/config-shared.ts` (`ExperimentalConfig`), the zod entry in `server/config-schema.ts`, a default in `defaultConfig`, and a `process.env.__NEXT_*` entry in `build/define-env.ts` when the flag must reach user-bundled code — with the `$flags` skill documenting the runtime-env plumbing needed for pre-compiled internals. — [packages/next/src/server/config-shared.ts#L501](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/packages/next/src/server/config-shared.ts#L501) [packages/next/src/server/config-schema.ts](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/packages/next/src/server/config-schema.ts) [packages/next/src/build/define-env.ts#L129-L270](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/packages/next/src/build/define-env.ts#L129-L270) [.agents/skills/flags/SKILL.md](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/.agents/skills/flags/SKILL.md)
- `RouteModule<D, U, X>` is the abstract base every route kind extends; adding a new kind means a new directory under `server/route-modules/` alongside `app-page`, `app-route`, `pages`, `pages-api`, plus a `RouteKind` entry in `server/route-kind.ts` and a definition in `server/route-definitions/`. — [packages/next/src/server/route-modules/route-module.ts#L77-L150](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/packages/next/src/server/route-modules/route-module.ts#L77-L150) [packages/next/src/server/route-kind.ts](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/packages/next/src/server/route-kind.ts) [packages/next/src/server/route-definitions/](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/packages/next/src/server/route-definitions/)
- Hosting platforms extend the build via `NextAdapter`: set `config.adapterPath` (or `NEXT_ADAPTER_PATH`) and export the adapter interface declared in `build/adapter/build-complete.ts`, which receives `AdapterOutput`/`AdapterOutputs` describing every emitted route including edge entries and their `handlerExport`. — [packages/next/src/build/adapter/build-complete.ts#L124-L499](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/packages/next/src/build/adapter/build-complete.ts#L124-L499) [packages/next/src/server/config-shared.ts#L1848](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/packages/next/src/server/config-shared.ts#L1848)
- Cache backends plug in two ways: the legacy `CacheHandler` class contract (`get`/`set`/`revalidateTag`) consumed by `IncrementalCache`, and the newer `"use cache"` handler registry populated by `setCacheHandler(kind, handler)` / `initializeCacheHandlers(cacheMaxMemorySize)` with a documented stream-ownership contract. — [packages/next/src/server/lib/incremental-cache/index.ts#L103-L125](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/packages/next/src/server/lib/incremental-cache/index.ts#L103-L125) [packages/next/src/server/use-cache/handlers.ts#L58-L95](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/packages/next/src/server/use-cache/handlers.ts#L58-L95) [packages/next/src/server/lib/cache-handlers/types.ts#L6-L60](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/packages/next/src/server/lib/cache-handlers/types.ts#L6-L60)
- A tiered cache composition point already exists (`createTieredCacheHandler` returning a `CacheReadWriteHandler`), with dev-only maps at `Symbol.for('@next/cache-handlers-dev-tiered')` and `-dev-fronts` for layering an in-memory front over a remote handler. — [packages/next/src/server/use-cache/handlers.ts#L1-L52](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/packages/next/src/server/use-cache/handlers.ts#L1-L52) [packages/next/src/server/use-cache/tiered-cache-handler.ts](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/packages/next/src/server/use-cache/tiered-cache-handler.ts)
- ESLint rules register in exactly one place: add the rule module under `packages/eslint-plugin-next/src/rules/`, import it in `src/index.ts`, and add entries to `plugin.rules` plus `recommendedRules` (and `coreWebVitalsRules` if it should escalate). — [packages/eslint-plugin-next/src/index.ts#L1-L80](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/packages/eslint-plugin-next/src/index.ts#L1-L80)
- The `@gate` condition registry in `test/lib/gate/conditions.ts` is a deliberate hand-written extension point — declare a `staticCondition` (available to `@force-gate`) or a `lazyCondition` reading the fixture's resolved config; referencing an undeclared name is a hard collection-time error. — [test/lib/gate/conditions.ts#L1-L70](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/test/lib/gate/conditions.ts#L1-L70)
- New test suites are scaffolded, not hand-written: `pnpm new-test --args <appDir> <name> <type>` runs a `turbo gen test` plop generator (types `e2e | production | development | unit`), and `pnpm new-error` generates an `errors/*.mdx` page the same way. — [package.json#L4-L6](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/package.json#L4-L6) [AGENTS.md](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/AGENTS.md)
- Codemods extend via `packages/next-codemod/transforms/` with colocated `__testfixtures__` and `__tests__` directories, and are surfaced to users through `next upgrade`. — [packages/next-codemod/transforms/](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/packages/next-codemod/transforms/) [packages/next/src/cli/next-upgrade.ts](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/packages/next/src/cli/next-upgrade.ts)
- Turbopack's Rust side extends through `#[turbo_tasks::function]` methods on `Project` / `ProjectContainer` in `crates/next-api/src/project.rs`, which are then exposed to JS by adding a napi binding and a corresponding method on `ProjectImpl` in `packages/next/src/build/swc/index.ts`. — [crates/next-api/src/project.rs#L919-L1045](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/crates/next-api/src/project.rs#L919-L1045) [packages/next/src/build/swc/index.ts#L683-L835](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/packages/next/src/build/swc/index.ts#L683-L835) [crates/next-napi-bindings/src/lib.rs](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/crates/next-napi-bindings/src/lib.rs)
- Bundled third-party deps extend through `packages/next/taskfile.js`: register `externals['pkg'] = 'next/dist/compiled/pkg'` and add an `ncc_pkg` task, which is what keeps `next` dependency-light at install time. — [packages/next/taskfile.js#L100-L200](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/packages/next/taskfile.js#L100-L200) [packages/next/package.json#L100-L110](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/packages/next/package.json#L100-L110)
- Agent workflows are themselves an extension point: `.agents/skills/` holds 20 skill directories (`flags`, `dce-edge`, `react-vendoring`, `router-act`, `gate-tests`, `pr-status-triage`, `create-pr`, `backport-pr`, …) and `authoring-skills` documents the frontmatter spec and the AGENTS.md-vs-skill split. — [.agents/skills/README.md](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/.agents/skills/README.md) [.agents/skills/authoring-skills/SKILL.md](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/.agents/skills/authoring-skills/SKILL.md) [AGENTS.md](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/AGENTS.md)
- `create-next-app` extends through `packages/create-next-app/templates/`, driven by `create-app.ts`, so adding a starter variant is a template-directory change rather than CLI surgery. — [packages/create-next-app/create-app.ts](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/packages/create-next-app/create-app.ts) [packages/create-next-app/templates/](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/packages/create-next-app/templates/) [packages/create-next-app/index.ts](https://github.com/vercel/next.js/blob/2861a364fcbe75fe96b0b9127f9b335edfcf288c/packages/create-next-app/index.ts)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
