---
title: "Route Discovery"
description: "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..."
last_updated: "2026-10-12T06:38:56.85659+00:00"
canonical_url: "https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/build-system/route-discovery"
---

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [packages/next/src/server/lib/router-utils/filesystem.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/filesystem.ts)
- [packages/next/src/build/webpack/loaders/next-app-loader/index.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/webpack/loaders/next-app-loader/index.ts)
- [packages/next/src/build/index.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/index.ts)
- [packages/next/src/cli/internal/static-routes-info.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/cli/internal/static-routes-info.ts)
- [packages/next/src/build/adapter/build-complete.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/adapter/build-complete.ts)
- [packages/next/src/build/segment-config/app/app-segments.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/segment-config/app/app-segments.ts)
- [packages/next/src/build/route-discovery.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/route-discovery.ts)
- [packages/next/src/server/lib/router-utils/route-types-utils.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/route-types-utils.ts)
- [packages/next/src/build/handle-entrypoints.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/handle-entrypoints.ts)
- [packages/next/src/server/lib/router-utils/setup-dev-bundler.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts)
- [packages/next/src/build/utils.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/utils.ts)
- [packages/next/src/server/lib/router-utils/typegen.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/typegen.ts)
- [packages/next/src/build/validate-app-paths.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/validate-app-paths.ts)
- [packages/next/src/build/static-paths/app.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/static-paths/app.ts)
- [packages/next/src/server/app-render/segment-explorer-path.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/segment-explorer-path.ts)
- [packages/next/src/server/app-render/instant-validation/instant-validation.tsx](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/instant-validation/instant-validation.tsx)
- [packages/next/src/server/route-modules/route-module.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/route-modules/route-module.ts)
- [packages/next/src/build/segment-config/app/app-segment-config.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/segment-config/app/app-segment-config.ts)
- [packages/next/src/server/typescript/rules/config.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/config.ts)
- [packages/next/src/build/file-classifier.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/file-classifier.ts)
- [packages/next/src/build/generate-routes-manifest.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/generate-routes-manifest.ts)
</details>

## 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/route-discovery.ts#L101-L131), [packages/next/src/server/lib/router-utils/filesystem.ts:372-396](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/filesystem.ts#L372-L396). It serves as the foundational pipeline layer that unifies production builds and [Build Pipeline](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/build-system/build-pipeline) initialization by extracting route modules, parallel slots, layout trees, and API handlers [packages/next/src/build/index.ts:1658-1669](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/index.ts#L1658-L1669), [packages/next/src/server/lib/router-utils/route-types-utils.ts:214-236](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/route-types-utils.ts#L214-L236). 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/validate-app-paths.ts#L202-L278), [packages/next/src/build/segment-config/app/app-segments.ts:183-286](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/segment-config/app/app-segments.ts#L183-L286). 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/index.ts#L1646-L1687), [packages/next/src/server/lib/router-utils/setup-dev-bundler.ts:725-814](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts#L725-L814).

## 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/route-discovery.ts#L101-L131). It relies on `recursiveReadDir` with a `pathnameFilter` checking valid [app router](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/client-runtime/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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/route-discovery.ts#L109-L116). 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/route-discovery.ts#L118-L130).

```typescript
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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/route-discovery.ts#L101-L131)

### 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/route-discovery.ts#L136-L143). 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/route-discovery.ts#L63-L96).

```typescript
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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/route-discovery.ts#L77-L96)

> [!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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/route-discovery.ts#L84-L91)

### 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/route-discovery.ts#L166-L214). 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/route-discovery.ts#L35-L36), [packages/next/src/build/route-discovery.ts:148-161](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/route-discovery.ts#L148-L161). 

```typescript
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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/route-discovery.ts#L148-L161)

| 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/route-discovery.ts#L35-L36), [packages/next/src/build/route-discovery.ts:154-160](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/route-discovery.ts#L154-L160)

## 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/file-classifier.ts#L13-L25). 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/file-classifier.ts#L5-L6), [packages/next/src/build/file-classifier.ts:18-20](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/file-classifier.ts#L18-L20).

```typescript
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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/file-classifier.ts#L5-L25)

> [!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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/file-classifier.ts#L1-L2), [packages/next/src/build/file-classifier.ts:13-22](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/file-classifier.ts#L13-L22)

### 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/file-classifier.ts#L30-L70). 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/file-classifier.ts#L30-L70).

```typescript
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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/file-classifier.ts#L57-L70)

### 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/segment-explorer-path.ts#L12-L55). 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/segment-explorer-path.ts#L5-L7), [packages/next/src/server/app-render/segment-explorer-path.ts:57-73](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/segment-explorer-path.ts#L57-L73).

```typescript
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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/segment-explorer-path.ts#L57-L73)

| 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/segment-explorer-path.ts#L3), [packages/next/src/server/app-render/segment-explorer-path.ts:82](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/segment-explorer-path.ts#L82), [packages/next/src/server/app-render/segment-explorer-path.ts:89](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/segment-explorer-path.ts#L89)

## 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/validate-app-paths.ts#L16-L53). 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/validate-app-paths.ts#L16-L53).

```typescript
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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/validate-app-paths.ts#L16-L53)

> [!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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/validate-app-paths.ts#L29-L38).

Sources: [packages/next/src/build/validate-app-paths.ts:29-38](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/validate-app-paths.ts#L29-L38)

### 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/validate-app-paths.ts#L61-L139), [packages/next/src/build/validate-app-paths.ts:202-281](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/validate-app-paths.ts#L202-L281). For interception routes, validation recursively verifies both intercepting and intercepted branches separately [packages/next/src/build/validate-app-paths.ts:64-68](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/validate-app-paths.ts#L64-L68).

```typescript
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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/validate-app-paths.ts#L61-L68)

| 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/validate-app-paths.ts#L18-L137), [packages/next/src/build/validate-app-paths.ts:231-240](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/validate-app-paths.ts#L231-L240), [packages/next/src/build/validate-app-paths.ts:257-277](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/validate-app-paths.ts#L257-L277)

> [!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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/validate-app-paths.ts#L104-L114).

Sources: [packages/next/src/build/validate-app-paths.ts:104-114](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/validate-app-paths.ts#L104-L114)

## 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](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/server-runtime/route-handlers) [packages/next/src/build/segment-config/app/app-segment-config.ts:1-38](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/segment-config/app/app-segment-config.ts#L1-L38). 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/segment-config/app/app-segment-config.ts#L97-L173).

```typescript
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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/segment-config/app/app-segment-config.ts#L97-L173)

> [!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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/segment-config/app/app-segment-config.ts#L153-L157).

Sources: [packages/next/src/build/segment-config/app/app-segment-config.ts:153-157](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/segment-config/app/app-segment-config.ts#L153-L157)

### 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/segment-config/app/app-segment-config.ts#L181-L223). If validation fails, `formatZodError` formats the error message alongside documentation references [packages/next/src/build/segment-config/app/app-segment-config.ts:225-230](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/segment-config/app/app-segment-config.ts#L225-L230).

```typescript
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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/segment-config/app/app-segment-config.ts#L181-L230)

| 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/segment-config/app/app-segment-config.ts#L97-L173), [packages/next/src/build/segment-config/app/app-segment-config.ts:187-216](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/segment-config/app/app-segment-config.ts#L187-L216)

## 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts#L18). When changes occur in source directories, the development bundler re-scans filesystem paths and reconciles route definitions.

```typescript
import Watchpack from 'next/dist/compiled/watchpack'
```
Sources: [packages/next/src/server/lib/router-utils/setup-dev-bundler.ts:18](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts#L18)

> [!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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts#L754-L755).

Sources: [packages/next/src/server/lib/router-utils/setup-dev-bundler.ts:754-755](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts#L754-L755)

### 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts#L819-L869). 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts#L883-L901).

```typescript
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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts#L883-L901)

> [!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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts#L886-L897).

Sources: [packages/next/src/server/lib/router-utils/setup-dev-bundler.ts:886-897](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts#L886-L897)

## 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/route-types-utils.ts#L38-L57). 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/route-types-utils.ts#L62-L66), [packages/next/src/server/lib/router-utils/route-types-utils.ts:380-415](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/route-types-utils.ts#L380-L415). 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/route-types-utils.ts#L33-L36), [packages/next/src/server/lib/router-utils/route-types-utils.ts:238-247](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/route-types-utils.ts#L238-L247).

```typescript
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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/route-types-utils.ts#L38-L57)

> [!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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/route-types-utils.ts#L315-L319), [packages/next/src/server/lib/router-utils/route-types-utils.ts:340-344](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/route-types-utils.ts#L340-L344).

Sources: [packages/next/src/server/lib/router-utils/route-types-utils.ts:315-319](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/route-types-utils.ts#L315-L319), [packages/next/src/server/lib/router-utils/route-types-utils.ts:340-344](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/route-types-utils.ts#L340-L344)

### 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/typegen.ts#L459-L521). 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/route-types-utils.ts#L435-L440).

| 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/typegen.ts#L510-L518) |
| `generateValidatorFileStrict` | `AppPageConfig`, `LayoutConfig`, `RouteHandlerConfig`, `PagesPageConfig`, `ApiRouteConfig` | `handler satisfies ${typeWithRoute}` [packages/next/src/server/lib/router-utils/typegen.ts:760-765](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/typegen.ts#L760-L765) |

Sources: [packages/next/src/server/lib/router-utils/typegen.ts:510-518](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/typegen.ts#L510-L518), [packages/next/src/server/lib/router-utils/typegen.ts:760-765](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/typegen.ts#L760-L765)

> [!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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/typegen.ts#L475-L477), [packages/next/src/server/lib/router-utils/typegen.ts:727-730](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/typegen.ts#L727-L730).

Sources: [packages/next/src/server/lib/router-utils/typegen.ts:475-477](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/typegen.ts#L475-L477), [packages/next/src/server/lib/router-utils/typegen.ts:727-730](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/typegen.ts#L727-L730)

## 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/generate-routes-manifest.ts#L53-L118). 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/generate-routes-manifest.ts#L121-L136).

| Property Name | Source / Value Expression | Purpose |
| :--- | :--- | :--- |
| `version` | `3` | Defines manifest schema version compatibility [packages/next/src/build/generate-routes-manifest.ts:98-98](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/generate-routes-manifest.ts#L98-L98) |
| `pages404` | `true` | Indicates built-in fallback 404 page handling [packages/next/src/build/generate-routes-manifest.ts:99-99](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/generate-routes-manifest.ts#L99-L99) |
| `caseSensitive` | `!!config.experimental.caseSensitiveRoutes` | Toggles case-sensitive URL matching [packages/next/src/build/generate-routes-manifest.ts:101-101](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/generate-routes-manifest.ts#L101-L101) |
| `rsc.header` | `RSC_HEADER` | Identifies React Server Component requests [packages/next/src/build/generate-routes-manifest.ts:121-122](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/generate-routes-manifest.ts#L121-L122) |
| `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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/generate-routes-manifest.ts#L125-L125) |
| `ppr` | `{ chain: { headers: { [NEXT_RESUME_HEADER]: '1' } } }` | Configures Partial Prerendering header chains when enabled [packages/next/src/build/generate-routes-manifest.ts:143-151](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/generate-routes-manifest.ts#L143-L151) |

Sources: [packages/next/src/build/generate-routes-manifest.ts:98-151](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/generate-routes-manifest.ts#L98-L151)

> [!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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/generate-routes-manifest.ts#L143-L151).

Sources: [packages/next/src/build/generate-routes-manifest.ts:143-151](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/generate-routes-manifest.ts#L143-L151)

### 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/cli/internal/static-routes-info.ts#L212-L230). 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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/cli/internal/static-routes-info.ts#L231-L307).

```mermaid
flowchart TD
    A[Discover Routes] --> B[pages-manifest.json]
    A --> C[app-paths-manifest.json]
    A --> D[middleware-manifest.json]
    B --> E{Edge Function?}
    C --> E
    E -- Yes --> F[Edge Runtime Kind]
    E -- No --> G{Entry File Type}
    G -- .js --> H[Node Runtime Server Entry]
    G -- .html --> I[Pages Static Prerender]
```

Sources: [packages/next/src/cli/internal/static-routes-info.ts:212-307](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/cli/internal/static-routes-info.ts#L212-L307)

> [!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](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/cli/internal/static-routes-info.ts#L288-L297).

Sources: [packages/next/src/cli/internal/static-routes-info.ts:288-297](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/cli/internal/static-routes-info.ts#L288-L297)

## Related

- [Build Pipeline](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/build-system/build-pipeline)
- [Manifest Plugins](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/build-system/manifest-plugins)


## Sitemap

See the full [sitemap](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/llms.txt) for all pages in this wiki.
