Architecture Overview
Server Runtime
Rendering Pipeline
Client Navigation
Caching and Export
Development Tools
Build and Configuration
Ecosystem Packages
Testing Infrastructure
How It Works
The following files were used as context for generating this wiki page:
Routing and Normalization in Next.js serves as the foundational canonicalization engine responsible for parsing, validating, and transforming incoming HTTP request URLs, client transitions, and internal build artifacts before they reach route matchers, middleware, or page renderers. Incoming requests often carry environmental artifacts such as configured basePath prefixes, internationalization locale segments, internal Next.js data request structures, React Server Component extensions, and malformed slashes.
The normalization subsystem addresses these issues by executing structured extraction pipelines across both client and server boundaries, decoupling structural concerns via specialized normalizer classes and utility functions.
getNextPathnameInfo)The core analytical primitive for parsing request paths is getNextPathnameInfo, located in packages/next/src/shared/lib/router/utils/get-next-pathname-info.ts. This utility inspects a raw pathname string against configuration parameters and extracts metadata into an interface called NextPathnameInfo.
The extraction routine checks trailing slashes, strips basePath prefixes, parses Next.js data URLs beginning with /_next/data/, and detects locales via normalizeLocalePath or i18nProvider.analyze.
export interface NextPathnameInfo {
basePath?: string
buildId?: string
locale?: string
pathname: string
trailingSlash?: boolean
}Note
When parsing Next.js data URLs, getNextPathnameInfo retains the original data prefix for metadata extraction while providing a normalized inner pathname when parseData: true is set.
Next.js implements an extensible object-oriented normalizer pattern defined by the Normalizer and PathnameNormalizer interfaces.
These classes encapsulate specific URL manipulation behaviors, such as stripping base paths, handling .json data suffixes, segment prefetch RSC extensions, and bundle path transformations.
The server instance maintains a prioritized array of normalizers in BaseServer.normalize to evaluate requests sequentially.
Each normalizer implements a guard method match(pathname) prior to executing normalize(pathname). For instance, PrefixPathnameNormalizer explicitly validates constructor parameters.
i18n) Locale Detection and Path NormalizationInternationalization routing requires detecting locales from the request pathname, subdomains, cookies, or Accept-Language headers, and normalizing the path by stripping the locale prefix.
This is handled by normalizeLocalePath, I18NProvider, and routing resolvers.
The normalizeLocalePath function splits the pathname by / to inspect the second segment, utilizing a WeakMap cache for performance.
const cache = new WeakMap<readonly string[], readonly string[]>()
export function normalizeLocalePath(
pathname: string,
locales?: readonly string[]
): PathLocale {
if (!locales) return { pathname }
let lowercasedLocales = cache.get(locales)
if (!lowercasedLocales) {
lowercasedLocales = locales.map((locale) => locale.toLowerCase())
cache.set(locales, lowercasedLocales)
}
const segments = pathname.split('/', 2)
if (!segments[1]) return { pathname }
const segment = segments[1].toLowerCase()
const index = lowercasedLocales.indexOf(segment)
if (index < 0) return { pathname }
const detectedLocale = locales[index]
pathname = pathname.slice(detectedLocale.length + 1) || '/'
return { pathname, detectedLocale }
}Warning
When i18n is configured, failing to account for locale prefixes when resolving filesystem items can result in route matching collisions or 404 errors, as app directory routes do not match i18n locale prefixes directly.
/_next/data/)Client-side data fetching for Static Generation and Server-Side Rendering utilizes JSON data files mapped under /_next/data/{buildId}/{path}.json.
The normalization engine converts these data request URLs back into standard page pathnames for routing and execution.
Both client-side utilities and server-side router utils perform this canonicalization via normalizeDataPath:
export function normalizeDataPath(pathname: string) {
if (!pathHasPrefix(pathname || '/', '/_next/data')) {
return pathname
}
pathname = pathname
.replace(/\/_next\/data\/[^/]{1,}/, '')
.replace(/\.json$/, '')
if (pathname === '/index') {
return '/'
}
return pathname
}Conversely, denormalization reconstructs the data URL format by injecting the build ID and .json extension.
normalizeAppPath)In the App Router (app/ directory), file paths on disk include structural syntax such as route groups, parallel route slots, and leaf filenames.
The normalizeAppPath function strips these markers to derive the public request pathname.
export function normalizeAppPath(route: string) {
return ensureLeadingSlash(
route.split('/').reduce((pathname, segment, index, segments) => {
if (!segment) {
return pathname
}
if (isGroupSegment(segment)) {
return pathname
}
if (segment[0] === '@') {
return pathname
}
if (
(segment === 'page' || segment === 'route') &&
index === segments.length - 1
) {
return pathname
}
return `${pathname}/${segment}`
}, '')
)
}To correctly prioritize parallel slot paths during route matching and manifest loading, Next.js employs compareAppPaths.
Important
compareAppPaths ensures that parallel slot paths containing /@ sort before children page paths. Without this, route group prefixes like (group) would sort before @, leading to manifest mismatches in development mode.
When an incoming HTTP request is received by the Next.js server, it undergoes a rigorous validation and normalization pipeline before middleware or route handlers execute.
The pipeline checks for repeated slashes and backslashes, constructs absolute initialization URLs, peels locale and basePath prefixes, and tags data requests.
The routing and normalization subsystem relies on configuration properties defined in next.config.js and internal request headers.
Sources: packages/next/src/shared/lib/router/utils/get-next-pathname-info.ts:40-44, packages/next/src/server/lib/router-utils/resolve-routes.ts:193-202
The routing and normalization architecture balances performance, flexibility, and compliance with HTTP standards through deliberate design choices.
Sources: packages/next/src/shared/lib/i18n/normalize-locale-path.ts:8-11, packages/next/src/shared/lib/router/utils/app-paths.ts:23-52