Routing Architecture
Pack:
next-intlParent skill: Next Intl Routing and Navigation Source:next-intl/next-intl-routing-and-navigation/references/routing-architecture.md
Read this when
Section titled “Read this when”- setting up locale routing for the first time
- refactoring
routing.ts,proxy.ts, or navigation helpers - debugging locale negotiation, redirects, rewrites, or locale-aware links
Canonical mental model
Section titled “Canonical mental model”- Keep
src/i18n/routing.tsas the single source of truth. - Use
defineRouting(...)to declarelocales,defaultLocale, and any routing behavior likelocalePrefix,pathnames,domains,localeDetection,localeCookie, oralternateLinks. - Use
createMiddleware(routing)at the edge negotiation layer. - Use
createNavigation(routing)for locale-awareLink,redirect,useRouter,usePathname, andgetPathname. - Use
i18n/request.tsto validaterequestLocaleand expose the resolved locale to the render tree. - If locales are dynamic at runtime, provide routing to the middleware per request and keep any custom navigation config in sync.
Stable App Router shape
Section titled “Stable App Router shape”import {defineRouting} from 'next-intl/routing';
export const routing = defineRouting({ locales: ['en', 'de'], defaultLocale: 'en'});import createMiddleware from 'next-intl/middleware';import {routing} from '@/i18n/routing';
export default createMiddleware(routing);
export const config = { matcher: '/((?!api|trpc|_next|_vercel|.*\\..*).*)'};import {createNavigation} from 'next-intl/navigation';import {routing} from '@/i18n/routing';
export const {Link, redirect, usePathname, useRouter, getPathname} = createNavigation(routing);Locale validation rules
Section titled “Locale validation rules”- Validate
requestLocalewithhasLocale(routing.locales, requested). - Expect
requestLocaleto be:- overridden when an explicit locale is passed to awaitable APIs
undefinedoutside the[locale]segment- invalid when unknown leading segments hit
[locale]
- Fall back to
routing.defaultLocaleinside request config when recovery is acceptable. - Use
notFound()in routed pages and layouts when the URL locale is invalid.
Negotiation and persistence
Section titled “Negotiation and persistence”localeDetection: falsedisablesaccept-languageand cookie-based locale detection. Only the URL or matching domain decides the locale.localeCookiecontrols theNEXT_LOCALEpreference cookie. Customize it when persistence duration or cookie naming matters, or disable it explicitly.localePrefix: 'as-needed'andlocalePrefix: 'never'require matcher coverage for unprefixed URLs.localePrefix: 'never'rewrites internally to[locale]routes and disables automatic alternate links.
Navigation rules
Section titled “Navigation rules”- Import navigation helpers from one shared module, not directly from
next/navigation. - Keep locale-switcher behavior aligned with the routing config and current pathname.
- Generate localized URLs from
getPathnameor localizedLink, not manual string concatenation. - Treat
getPathname(...)as the canonical URL builder for sitemap and alternate-link work, but prependbasePathmanually when needed.
Matcher footguns
Section titled “Matcher footguns”- Exclude framework internals and dot-files or locale negotiation will interfere with assets.
- Revisit the matcher when you add custom locale prefixes,
basePath, or non-standard app shells. - When
basePathis enabled, include'/'in the matcher because the matcher is evaluated relative to the base path. - Remember that Next.js 16 renamed
middleware.tstoproxy.ts; older code may still use the prior filename.
Source map
Section titled “Source map”https://next-intl.dev/docs/routing/setuphttps://next-intl.dev/docs/routing/configurationhttps://next-intl.dev/docs/usage/configurationhttps://next-intl.dev/docs/environments/actions-metadata-route-handlers