Relevant source files
The following files were used as context for generating this wiki page:
- packages/next/src/server/lib/router-utils/filesystem.ts
- packages/next/src/build/webpack/loaders/next-app-loader/index.ts
- packages/next/src/build/index.ts
- packages/next/src/cli/internal/static-routes-info.ts
- packages/next/src/build/adapter/build-complete.ts
- packages/next/src/build/segment-config/app/app-segments.ts
- packages/next/src/build/route-discovery.ts
- packages/next/src/server/lib/router-utils/route-types-utils.ts
- packages/next/src/build/handle-entrypoints.ts
- packages/next/src/server/lib/router-utils/setup-dev-bundler.ts
- packages/next/src/build/utils.ts
- packages/next/src/server/lib/router-utils/typegen.ts
- packages/next/src/build/validate-app-paths.ts
- packages/next/src/build/static-paths/app.ts
- packages/next/src/server/app-render/segment-explorer-path.ts
- packages/next/src/server/app-render/instant-validation/instant-validation.tsx
- packages/next/src/server/route-modules/route-module.ts
- packages/next/src/build/segment-config/app/app-segment-config.ts
- packages/next/src/server/typescript/rules/config.ts
- packages/next/src/build/file-classifier.ts
- packages/next/src/build/generate-routes-manifest.ts
Overview
Route Discovery handles locating, scanning, and processing all file-based endpoints across the pages and app directories, turning filesystem conventions into structured route metadata and manifests packages/next/src/build/route-discovery.ts:101-131, packages/next/src/server/lib/router-utils/filesystem.ts:372-396. It serves as the foundational pipeline layer that unifies production builds and Build Pipeline initialization by extracting route modules, parallel slots, layout trees, and API handlers packages/next/src/build/index.ts:1658-1669, packages/next/src/server/lib/router-utils/route-types-utils.ts:214-236. By validating parameter syntax, preventing routing conflicts, and parsing segment-level configuration exports, the component ensures runtime and compile-time consistency packages/next/src/build/validate-app-paths.ts:202-278, packages/next/src/build/segment-config/app/app-segments.ts:183-286. Ultimately, it coordinates synchronization with development filesystem watchers and serializes static analysis artifacts and route type manifests packages/next/src/build/index.ts:1646-1687, packages/next/src/server/lib/router-utils/setup-dev-bundler.ts:725-814.
Filesystem Scanning and Route Collection
Scanning and Collecting App Directory Files
The collectAppFiles function scans the designated app directory recursively to extract paths for application pages, layouts, and default entries packages/next/src/build/route-discovery.ts:101-131. It relies on recursiveReadDir with a pathnameFilter checking valid app router pages, root not-found boundaries, app layout pages, and default pages, while ignoring any file or folder paths starting with an underscore via ignorePartFilter packages/next/src/build/route-discovery.ts:109-116. Once the raw file list is retrieved, filter predicates segregate them into distinct collections for application paths, layout paths, and default paths packages/next/src/build/route-discovery.ts:118-130.
export async function collectAppFiles(
appDir: string,
validFileMatcher: ReturnType<typeof createValidFileMatcher>
): Promise<{
appPaths: string[]
layoutPaths: string[]
defaultPaths: string[]
}> {
const allAppFiles = await recursiveReadDir(appDir, {
pathnameFilter: (absolutePath) =>
validFileMatcher.isAppRouterPage(absolutePath) ||
validFileMatcher.isRootNotFound(absolutePath) ||
validFileMatcher.isAppLayoutPage(absolutePath) ||
validFileMatcher.isAppDefaultPage(absolutePath),
ignorePartFilter: (part) => part.startsWith('_'),
})
const appPaths = allAppFiles.filter(
(absolutePath) =>
validFileMatcher.isAppRouterPage(absolutePath) ||
validFileMatcher.isRootNotFound(absolutePath)
)
const layoutPaths = allAppFiles.filter((absolutePath) =>
validFileMatcher.isAppLayoutPage(absolutePath)
)
const defaultPaths = allAppFiles.filter((absolutePath) =>
validFileMatcher.isAppDefaultPage(absolutePath)
)
return { appPaths, layoutPaths, defaultPaths }
}Sources: packages/next/src/build/route-discovery.ts:101-131
Scanning Pages Directory and Path Normalization
The collectPagesFiles function queries the traditional pages directory utilizing recursiveReadDir filtered specifically by validFileMatcher.isPageFile packages/next/src/build/route-discovery.ts:136-143. To transform raw filesystem absolute paths into logical routes or relative entries, helper functions such as getPageFromPath, normalizeAppRoute, and normalizeLayoutRoute process path strings by sorting and removing extensions by decreasing length and stripping router segment suffixes packages/next/src/build/route-discovery.ts:63-96.
export function getPageFromPath(
pagePath: string,
pageExtensions: PageExtensions
) {
let page = normalizePathSep(pagePath)
// Try longer extensions first so compound extensions like 'page.js'
// match before shorter ones like 'js'
const sorted = [...pageExtensions].sort((a, b) => b.length - a.length)
for (const extension of sorted) {
const next = removeSuffix(page, `.${extension}`)
if (next !== page) {
page = next
break
}
}
page = removeSuffix(page, '/index')
return page === '' ? '/' : page
}Sources: packages/next/src/build/route-discovery.ts:77-96
Note
Extension sorting within getPageFromPath sorts pageExtensions by descending length (b.length - a.length) to ensure compound extensions like .page.js take precedence over shorter substrings like .js.
Sources: packages/next/src/build/route-discovery.ts:84-91
Processing Mapped Routes and Relative File Paths
The route processing pipeline converts mapped route dictionaries into structured RouteInfo arrays via processPageRoutes and processAppRoutes packages/next/src/build/route-discovery.ts:166-214. Each mapped entry constructs a relative file path using createRelativeFilePath, applying prefix regular expressions (PRIVATE_PAGES_PREFIX_REGEX or PRIVATE_APP_PREFIX_REGEX) alongside source directory indicators packages/next/src/build/route-discovery.ts:35-36, packages/next/src/build/route-discovery.ts:148-161.
export function createRelativeFilePath(
baseDir: string,
filePath: string,
prefix: 'pages' | 'app',
isSrcDir: boolean
): string {
const privatePrefixRegex =
prefix === 'pages' ? PRIVATE_PAGES_PREFIX_REGEX : PRIVATE_APP_PREFIX_REGEX
const srcPrefix = isSrcDir ? 'src/' : ''
return join(
baseDir,
filePath.replace(privatePrefixRegex, `${srcPrefix}${prefix}/`)
)
}Sources: packages/next/src/build/route-discovery.ts:148-161
| Prefix Type | Internal Regex Constant | Target Directory Replacement |
|---|---|---|
pages | PRIVATE_PAGES_PREFIX_REGEX (/^private-next-pages\//) | [src/]pages/ |
app | PRIVATE_APP_PREFIX_REGEX (/^private-next-app-dir\//) | [src/]app/ |
Sources: packages/next/src/build/route-discovery.ts:35-36, packages/next/src/build/route-discovery.ts:154-160
Route Segments and Slot Classification
Parallel Route Slot Extraction
Parallel routes in the App Router are identified by slot folders prefixed with an @ symbol. The classification engine extracts slot metadata from path strings by iterating backward through path segments until it encounters a parallel route segment verified by isParallelRouteSegment packages/next/src/build/file-classifier.ts:13-25. The resulting SlotInfo structure pairs the normalized parent route path with the slot name stripped of its leading @ character packages/next/src/build/file-classifier.ts:5-6, packages/next/src/build/file-classifier.ts:18-20.
export type SlotInfo = { name: string; parent: string }
// Route information for route manifests
export type RouteInfo = { route: string; filePath: string }
/**
* Extract slot info from a page path if it contains a parallel route
*/
export function extractSlotFromPath(pagePath: string): SlotInfo | undefined {
const segments = pagePath.split('/')
for (let i = segments.length - 1; i >= 0; i--) {
const segment = segments[i]
if (isParallelRouteSegment(segment)) {
return {
name: segment.slice(1),
parent: normalizeAppPath(segments.slice(0, i).join('/')),
}
}
}
return undefined
}Sources: packages/next/src/build/file-classifier.ts:5-25
Important
The parent path for a parallel route slot is computed by slicing path segments preceding the slot directory and passing them through normalizeAppPath, ensuring dynamic catch-all and optional parameters map correctly to their logical route parent.
Sources: packages/next/src/build/file-classifier.ts:1-2, packages/next/src/build/file-classifier.ts:13-22
Slot Collection and Deduplication
When aggregating slots across multiple route entries or route mapping dictionaries, the classifier filters out skipped routes and checks for uniqueness based on a composite key format combining slot name and parent path (${slot.name}:${slot.parent}) packages/next/src/build/file-classifier.ts:30-70. Functions such as addSlotIfNew, extractSlotsFromRoutes, and combineSlots maintain distinct slot collections by rejecting duplicate entries that share identical parent contexts and slot identifiers packages/next/src/build/file-classifier.ts:30-70.
export function combineSlots(...slotArrays: SlotInfo[][]): SlotInfo[] {
const slotSet = new Set<string>()
const result: SlotInfo[] = []
for (const slots of slotArrays) {
for (const slot of slots) {
const key = `${slot.name}:${slot.parent}`
if (!slotSet.has(key)) {
slotSet.add(key)
result.push(slot)
}
}
}
return result
}Sources: packages/next/src/build/file-classifier.ts:57-70
File Path Normalization and Convention Boundaries
File path classification handles project root directories, monorepo workspaces, and Turbopack path prefixes by stripping markers such as [project] or absolute working directories through normalizeFilePath packages/next/src/server/app-render/segment-explorer-path.ts:12-55. Convention files within the app directory are further processed via normalizeConventionFilePath to remove app/ or src/app/ prefixes, while built-in internal components matching nextInternalPrefixRegex receive a __next_builtin__ prefix packages/next/src/server/app-render/segment-explorer-path.ts:5-7, packages/next/src/server/app-render/segment-explorer-path.ts:57-73.
export function normalizeConventionFilePath(
projectDir: string,
conventionPath: string | undefined
) {
let relativePath = normalizeFilePath(projectDir, conventionPath)
// remove /(src/)?app/ dir prefix
.replace(/^(src\/)?app\//, '')
// If it's internal file only keep the filename, strip nextjs internal prefix
if (nextInternalPrefixRegex.test(relativePath)) {
relativePath = relativePath.replace(nextInternalPrefixRegex, '')
// Add a special prefix to let segment explorer know it's a built-in component
relativePath = `${BUILTIN_PREFIX}${relativePath}`
}
return relativePath
}Sources: packages/next/src/server/app-render/segment-explorer-path.ts:57-73
| Constant Name | Value | Purpose |
|---|---|---|
BUILTIN_PREFIX | __next_builtin__ | Identifies internal built-in components like global error boundaries. |
BOUNDARY_SUFFIX | @boundary | Suffix marker trimmed during boundary filename normalization. |
BOUNDARY_PREFIX | boundary: | Prefix identifying boundary file types in segment exploration trees. |
Sources: packages/next/src/server/app-render/segment-explorer-path.ts:3, packages/next/src/server/app-render/segment-explorer-path.ts:82, packages/next/src/server/app-render/segment-explorer-path.ts:89
App Path Validation and Matching
Segment Parameter Validation Invariants
The validateSegmentParam function inspects dynamic segment parameters against strict syntax and naming rules packages/next/src/build/validate-app-paths.ts:16-53. It enforces that parameter names are non-empty, reject illegal three-dot characters (…), guard against unescaped or unsupported optional syntax, and prohibit leading or trailing brackets or erroneous periods packages/next/src/build/validate-app-paths.ts:16-53.
function validateSegmentParam(param: SegmentParam, pathname: string): void {
// Check for empty parameter names
if (param.paramName.length === 0) {
throw new Error(`Parameter names cannot be empty in route "${pathname}".`)
}
// Check for three-dot character (…) instead of ...
if (param.paramName.includes('…')) {
throw new Error(
`Detected a three-dot character ('…') in parameter "${param.paramName}" in route "${pathname}". Did you mean ('...')?`
)
}
// Check for optional non-catch-all segments (not yet supported)
if (
param.paramType !== 'optional-catchall' &&
param.paramName.startsWith('[') &&
param.paramName.endsWith(']')
) {
throw new Error(
`Optional route parameters are not yet supported ("[${param.paramName}]") in route "${pathname}".`
)
}
// Check for extra brackets
if (param.paramName.startsWith('[') || param.paramName.endsWith(']')) {
throw new Error(
`Segment names may not start or end with extra brackets ('${param.paramName}') in route "${pathname}".`
)
}
// Check for erroneous periods
if (param.paramName.startsWith('.')) {
throw new Error(
`Segment names may not start with erroneous periods ('${param.paramName}') in route "${pathname}".`
)
}
}Sources: packages/next/src/build/validate-app-paths.ts:16-53
Warning
Optional non-catch-all segments like [param] are not yet supported and will immediately throw an error during validateSegmentParam execution packages/next/src/build/validate-app-paths.ts:29-38.
Sources: packages/next/src/build/validate-app-paths.ts:29-38
Route Consistency and Conflict Detection
The validateAppRoute and validateAppPaths functions check whole route structures for duplicate slugs, invalid catch-all positioning, and cross-path ambiguities packages/next/src/build/validate-app-paths.ts:61-139, packages/next/src/build/validate-app-paths.ts:202-281. For interception routes, validation recursively verifies both intercepting and intercepted branches separately packages/next/src/build/validate-app-paths.ts:64-68.
function validateAppRoute(route: NormalizedAppRoute): void {
// For interception routes, validate the intercepting and intercepted routes separately
// This allows the same parameter name to appear in both parts
if (isInterceptionAppRoute(route)) {
validateAppRoute(route.interceptingRoute)
validateAppRoute(route.interceptedRoute)
return
}Sources: packages/next/src/build/validate-app-paths.ts:61-68
| Error Condition | Trigger Rule | Target Route Context |
|---|---|---|
| Empty Parameter | param.paramName.length === 0 | Route pathname |
| Three-Dot Character | param.paramName.includes('…') | Route pathname |
| Optional Non-Catch-All | paramType !== 'optional-catchall' with brackets | Route pathname |
| Extra Brackets | Starts or ends with [ or ] | Route pathname |
| Erroneous Period | Starts with . | Route pathname |
| Duplicate Slug | Slug name re-used in dynamic path | Route pathname |
| Slug Name Collision | Normalized slug names differ only by non-word symbols | Route pathname |
| Mispositioned Catch-All | Catch-all or optional catch-all not at path end | Route pathname |
| Mixed Catch-All Types | Both required and optional catch-all at same level | Route pathname |
| Optional Catch-All Specificity | Same specificity as an optional catch-all route prefix | App paths / normalized structures |
| Ambiguous Routes | Multiple paths map to the same normalized structure | Conflict collection map |
Sources: packages/next/src/build/validate-app-paths.ts:18-137, packages/next/src/build/validate-app-paths.ts:231-240, packages/next/src/build/validate-app-paths.ts:257-277
Caution
Slug names are normalized via .replace(/\W/g, '') before duplicate checking; slug names differing solely by non-word symbols within a single dynamic path will trigger a validation failure packages/next/src/build/validate-app-paths.ts:104-114.
Sources: packages/next/src/build/validate-app-paths.ts:104-114
Segment Configuration Parsing and Validation
Zod Schema Validation Architecture
Segment configuration parsing is implemented using Zod schemas to validate exported route segment options across app layouts, pages, and route handlers packages/next/src/build/segment-config/app/app-segment-config.ts:1-38. The main validator, AppSegmentConfigSchema, enforces strict typing on properties including revalidate, dynamic, fetchCache, runtime, maxDuration, preferredRegion, and unstable_dynamicStaleTime packages/next/src/build/segment-config/app/app-segment-config.ts:97-173.
const AppSegmentConfigSchema = z.object({
/**
* The number of seconds to revalidate the page or false to disable revalidation.
*/
revalidate: z
.union([z.number().int().nonnegative(), z.literal(false)])
.optional(),
/**
* Whether the page supports dynamic parameters.
*/
dynamicParams: z.boolean().optional(),
/**
* The dynamic behavior of the page.
*/
dynamic: z
.enum(['auto', 'error', 'force-static', 'force-dynamic'])
.optional(),
/**
* The caching behavior of the page.
*/
fetchCache: z
.enum([
'auto',
'default-cache',
'only-cache',
'force-cache',
'force-no-store',
'default-no-store',
'only-no-store',
])
.optional(),
/**
* How this segment should be prefetched.
*/
instant: InstantConfigSchema.optional(),
/**
* Controls prefetching for this segment.
* - 'auto' (default) is a noop.
* - 'partial' enables Partial Prefetching. Only Cache Components are
* prefetched, not dynamic ones. When a static prefetch is insufficient,
* the segment may be prefetched with a runtime request instead.
* - 'force-disabled' disables prefetching for the segment.
*/
prefetch: PrefetchSchema.optional(),
/**
* Controls which rendering phases require static output for this segment.
*/
ensureStatic: EnsureStaticSchema.optional(),
/**
* The stale time for dynamic responses in seconds.
* Controls how long the client-side router cache retains dynamic page data.
* Pages only — not allowed in layouts.
*/
unstable_dynamicStaleTime: z.number().int().nonnegative().optional(),
/**
* The preferred region for the page.
*/
preferredRegion: z.union([z.string(), z.array(z.string())]).optional(),
/**
* The runtime to use for the page.
*/
runtime: z.enum(['edge', 'nodejs']).optional(),
/**
* The maximum duration for the page in seconds.
*/
maxDuration: z.number().int().nonnegative().optional(),
})Sources: packages/next/src/build/segment-config/app/app-segment-config.ts:97-173
Warning
The unstable_dynamicStaleTime configuration property is restricted to pages only and is invalid when defined inside layout segments packages/next/src/build/segment-config/app/app-segment-config.ts:153-157.
Sources: packages/next/src/build/segment-config/app/app-segment-config.ts:153-157
Error Mapping and Parsing Execution
The parseAppSegmentConfig function evaluates userland exports against AppSegmentConfigSchema using a custom error map that inspects top-level Zod issue paths packages/next/src/build/segment-config/app/app-segment-config.ts:181-223. If validation fails, formatZodError formats the error message alongside documentation references packages/next/src/build/segment-config/app/app-segment-config.ts:225-230.
export function parseAppSegmentConfig(
data: unknown,
route: string
): AppSegmentConfig {
const parsed = AppSegmentConfigSchema.safeParse(data, {
errorMap: (issue, ctx) => {
if (issue.path.length === 1) {
switch (issue.path[0]) {
case 'revalidate': {
return {
message: `Invalid revalidate value ${JSON.stringify(
ctx.data
)} on "${route}", must be a non-negative number or false`,
}
}
case 'instant': {
return {
// @TODO replace this link with a link to the docs when they are written
message: `Invalid instant value ${JSON.stringify(ctx.data)} on "${route}", must be \`true\`, \`false\`, or an object. Read more at https://nextjs.org/docs/messages/invalid-instant-configuration`,
}
}
case 'prefetch': {
return {
message: `Invalid prefetch value ${JSON.stringify(ctx.data)} on "${route}", must be "auto", "partial", or "force-disabled".`,
}
}
case 'ensureStatic': {
return {
message: `Invalid ensureStatic value ${JSON.stringify(ctx.data)} on "${route}", must be "auto", "shell", "prefetch", "navigation", or false.`,
}
}
case 'unstable_dynamicStaleTime': {
return {
message: `Invalid unstable_dynamicStaleTime value ${JSON.stringify(ctx.data)} on "${route}", must be a non-negative number`,
}
}
default:
}
}
return { message: ctx.defaultError }
},
})
if (!parsed.success) {
throw formatZodError(
`Invalid segment configuration options detected for "${route}". Read more at https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config`,
parsed.error
)
}Sources: packages/next/src/build/segment-config/app/app-segment-config.ts:181-230
| Config Property | Zod Validation Rule | Error Message Path |
|---|---|---|
revalidate | z.union([z.number().int().nonnegative(), z.literal(false)]).optional() | revalidate |
dynamic | z.enum(['auto', 'error', 'force-static', 'force-dynamic']).optional() | Default zod error |
fetchCache | z.enum(['auto', 'default-cache', 'only-cache', 'force-cache', 'force-no-store', 'default-no-store', 'only-no-store']).optional() | Default zod error |
instant | InstantConfigSchema.optional() | instant |
prefetch | PrefetchSchema.optional() | prefetch |
ensureStatic | EnsureStaticSchema.optional() | ensureStatic |
unstable_dynamicStaleTime | z.number().int().nonnegative().optional() | unstable_dynamicStaleTime |
runtime | z.enum(['edge', 'nodejs']).optional() | Default zod error |
maxDuration | z.number().int().nonnegative().optional() | Default zod error |
Sources: packages/next/src/build/segment-config/app/app-segment-config.ts:97-173, packages/next/src/build/segment-config/app/app-segment-config.ts:187-216
Development Route Watching and Synchronization
Filesystem Watchers and Watchpack Integration
In development mode, Next.js relies on filesystem watchers powered by Watchpack to monitor app and pages directories for file changes, additions, and deletions packages/next/src/server/lib/router-utils/setup-dev-bundler.ts:18. When changes occur in source directories, the development bundler re-scans filesystem paths and reconciles route definitions.
import Watchpack from 'next/dist/compiled/watchpack'Sources: packages/next/src/server/lib/router-utils/setup-dev-bundler.ts:18
Warning
Files or directories starting with _ inside the app directory are skipped during route collection, except for special convention files explicitly handled by valid file matchers packages/next/src/server/lib/router-utils/setup-dev-bundler.ts:754-755.
Sources: packages/next/src/server/lib/router-utils/setup-dev-bundler.ts:754-755
Conflict Detection and Error State Synchronization
During route synchronization, duplicate pages in the pages directory or conflicting paths between app and pages directories trigger error states via the hot reloader interface packages/next/src/server/lib/router-utils/setup-dev-bundler.ts:819-869. The synchronization loop computes conflicting app page paths and updates the HMR server error status accordingly packages/next/src/server/lib/router-utils/setup-dev-bundler.ts:883-901.
const numConflicting = conflictingAppPagePaths.size
conflictingPageChange = numConflicting - previousConflictingPagePaths.size
if (conflictingPageChange !== 0) {
if (numConflicting > 0) {
let errorMessage = `Conflicting app and page file${
numConflicting === 1 ? ' was' : 's were'
} found, please remove the conflicting files to continue:\n`
for (const p of conflictingAppPagePaths) {
const appPath = path.relative(dir, appPageFilePaths.get(p)!)
const pagesPath = path.relative(dir, pagesPageFilePaths.get(p)!)
errorMessage += ` "${pagesPath}" - "${appPath}"\n`
}
hotReloader.setHmrServerError(new Error(errorMessage))
} else if (numConflicting === 0) {
hotReloader.clearHmrServerError()
}
}Sources: packages/next/src/server/lib/router-utils/setup-dev-bundler.ts:883-901
Caution
If conflicting app and page files are detected (numConflicting > 0), an error message is assigned to the hot reloader server, blocking compilation until the conflicting files are removed packages/next/src/server/lib/router-utils/setup-dev-bundler.ts:886-897.
Sources: packages/next/src/server/lib/router-utils/setup-dev-bundler.ts:886-897
Route Types Manifest Generation
Manifest Construction and Route Classification
The RouteTypesManifest structure aggregates classified entries from page routes, app routes, layouts, route handlers, redirects, and rewrites packages/next/src/server/lib/router-utils/route-types-utils.ts:38-57. During createRouteTypesManifest, custom route sources in redirects and rewrites are parsed using convertCustomRouteSource to normalize bracket and dynamic segments packages/next/src/server/lib/router-utils/route-types-utils.ts:62-66, packages/next/src/server/lib/router-utils/route-types-utils.ts:380-415. Each route entry retains an extracted parameter group map and relative file path computed against the project root or validator target directory packages/next/src/server/lib/router-utils/route-types-utils.ts:33-36, packages/next/src/server/lib/router-utils/route-types-utils.ts:238-247.
export interface RouteTypesManifest {
appRoutes: Record<string, ManifestRouteInfo>
pageRoutes: Record<string, ManifestRouteInfo>
layoutRoutes: Record<string, ManifestRouteInfo & { slots: string[] }>
appRouteHandlerRoutes: Record<string, ManifestRouteInfo>
/** Map of redirect source => ManifestRouteInfo */
redirectRoutes: Record<string, ManifestRouteInfo>
/** Map of rewrite source => ManifestRouteInfo */
rewriteRoutes: Record<string, ManifestRouteInfo>
/** File paths for validation */
appPagePaths: Set<string>
pagesRouterPagePaths: Set<string>
layoutPaths: Set<string>
appRouteHandlers: Set<string>
pageApiRoutes: Set<string>
/** Direct mapping from file paths to routes for validation */
filePathToRoute: Map<string, string>
/** Root params collected from root layouts, with their possible runtime value types */
rootParams: Map<string, RootParamInfo>
}Sources: packages/next/src/server/lib/router-utils/route-types-utils.ts:38-57
Note
Internal application paths such as UNDERSCORE_GLOBAL_ERROR_ROUTE and UNDERSCORE_NOT_FOUND_ROUTE are explicitly filtered out when populating layoutRoutes and appRoutes manifest tables packages/next/src/server/lib/router-utils/route-types-utils.ts:315-319, packages/next/src/server/lib/router-utils/route-types-utils.ts:340-344.
Sources: packages/next/src/server/lib/router-utils/route-types-utils.ts:315-319, packages/next/src/server/lib/router-utils/route-types-utils.ts:340-344
Type and Validator Generation Modes
The type generator translates the manifest into TypeScript declarations, parameter union maps, and type verification wrappers packages/next/src/server/lib/router-utils/typegen.ts:459-521. Depending on config.experimental.strictRouteTypes, writeRouteTypesManifest selects between standard generation via generateRouteTypesFile and strict checking via generateRouteTypesFileStrict packages/next/src/server/lib/router-utils/route-types-utils.ts:435-440.
| Validator Function | Target Configuration | Validation Mechanism |
|---|---|---|
generateValidatorFile | AppPageConfig, LayoutConfig, RouteHandlerConfig, PagesPageConfig, ApiRouteConfig | type __Check = __IsExpected<typeof handler> with @ts-ignore bypass packages/next/src/server/lib/router-utils/typegen.ts:510-518 |
generateValidatorFileStrict | AppPageConfig, LayoutConfig, RouteHandlerConfig, PagesPageConfig, ApiRouteConfig | handler satisfies ${typeWithRoute} packages/next/src/server/lib/router-utils/typegen.ts:760-765 |
Sources: packages/next/src/server/lib/router-utils/typegen.ts:510-518, packages/next/src/server/lib/router-utils/typegen.ts:760-765
Caution
File validation strictly filters input paths to TypeScript extensions (.ts and .tsx), ignoring JavaScript files to avoid type inference limitations during boundary verification packages/next/src/server/lib/router-utils/typegen.ts:475-477, packages/next/src/server/lib/router-utils/typegen.ts:727-730.
Sources: packages/next/src/server/lib/router-utils/typegen.ts:475-477, packages/next/src/server/lib/router-utils/typegen.ts:727-730
Routes Manifest and Static Analysis Artifacts
Manifest Serialization and Header Configuration
The generateRoutesManifest function creates the primary routes-manifest.json structure, aggregating static and dynamic routes sorted via sortPages, custom redirects, headers, and rewrites packages/next/src/build/generate-routes-manifest.ts:53-118. It configures RSC request headers, vary headers, and prefetch routing metadata required by client-side navigation packages/next/src/build/generate-routes-manifest.ts:121-136.
| Property Name | Source / Value Expression | Purpose |
|---|---|---|
version | 3 | Defines manifest schema version compatibility packages/next/src/build/generate-routes-manifest.ts:98-98 |
pages404 | true | Indicates built-in fallback 404 page handling packages/next/src/build/generate-routes-manifest.ts:99-99 |
caseSensitive | !!config.experimental.caseSensitiveRoutes | Toggles case-sensitive URL matching packages/next/src/build/generate-routes-manifest.ts:101-101 |
rsc.header | RSC_HEADER | Identifies React Server Component requests packages/next/src/build/generate-routes-manifest.ts:121-122 |
rsc.varyHeader | ${RSC_HEADER}, ${NEXT_ROUTER_STATE_TREE_HEADER}, ${NEXT_ROUTER_PREFETCH_HEADER}, ${NEXT_ROUTER_SEGMENT_PREFETCH_HEADER} | Default vary header configuration for client router requests packages/next/src/build/generate-routes-manifest.ts:125-125 |
ppr | { chain: { headers: { [NEXT_RESUME_HEADER]: '1' } } } | Configures Partial Prerendering header chains when enabled packages/next/src/build/generate-routes-manifest.ts:143-151 |
Sources: packages/next/src/build/generate-routes-manifest.ts:98-151
Note
When isAppPPREnabled is true, the manifest includes Partial Prerendering configuration rules with NEXT_RESUME_HEADER support, enabling partial streaming resumption during dynamic execution packages/next/src/build/generate-routes-manifest.ts:143-151.
Sources: packages/next/src/build/generate-routes-manifest.ts:143-151
Static Route Discovery and Compilation Analysis
Static route and bundle analysis utilities inspect build-time artifacts such as pages-manifest.json, app-paths-manifest.json, and middleware-manifest.json to classify route entries packages/next/src/cli/internal/static-routes-info.ts:212-230. The discovery process evaluates edge functions, server node bundles, and statically pre-rendered components without executing application code packages/next/src/cli/internal/static-routes-info.ts:231-307.
Sources: packages/next/src/cli/internal/static-routes-info.ts:212-307
Warning
Turbopack writes placeholder entry values such as app-edge-has-no-entrypoint inside manifests for Edge routes; static analysis must resolve actual bundle files directly from the middleware-manifest.json entry rather than depending on direct file paths packages/next/src/cli/internal/static-routes-info.ts:288-297.
Sources: packages/next/src/cli/internal/static-routes-info.ts:288-297
Related
On This Page
OverviewFilesystem Scanning and Route CollectionScanning and Collecting App Directory FilesScanning Pages Directory and Path NormalizationProcessing Mapped Routes and Relative File PathsRoute Segments and Slot ClassificationParallel Route Slot ExtractionSlot Collection and DeduplicationFile Path Normalization and Convention BoundariesApp Path Validation and MatchingSegment Parameter Validation InvariantsRoute Consistency and Conflict DetectionSegment Configuration Parsing and ValidationZod Schema Validation ArchitectureError Mapping and Parsing ExecutionDevelopment Route Watching and SynchronizationFilesystem Watchers and Watchpack IntegrationConflict Detection and Error State SynchronizationRoute Types Manifest GenerationManifest Construction and Route ClassificationType and Validator Generation ModesRoutes Manifest and Static Analysis ArtifactsManifest Serialization and Header ConfigurationStatic Route Discovery and Compilation AnalysisRelated