Repository navigation
Routing and Proxy
📄 Mirrors
docs/routing-and-proxy.mdin the main repo — the repo version is canonical.
Status: planned / pre-release. This page documents the intended API of next-tongue. Nothing is published yet; names may change before v1.0. See ROADMAP.
Next.js 16 renamed middleware.ts to proxy.ts (exported function proxy, Node.js runtime). next-tongue does all request-dependent locale work there, so pages and layouts can stay static and cacheable. See ADR 0002.
// proxy.ts
import { createProxy } from 'next-tongue/proxy';
export const proxy = createProxy();
export const config = { matcher: ['/((?!api|_next|.*\\..*).*)'] };Matcher caveat:
.*\\..*skips every path containing a dot, so/de/blog/v1.2bypasses the proxy (no locale redirect). If you have dotted routes, exclude only real file extensions, e.g.'/((?!api|_next|.*\\.(?:ico|png|jpg|svg|txt|xml|webmanifest)$).*)'.
All pages live under app/[locale]/. The proxy guarantees that by the time a request reaches the app, the [locale] segment is a valid locale.
- If the pathname starts with a known locale prefix → pass through (and refresh the locale cookie if enabled).
- Otherwise, determine the locale: domain match → cookie →
Accept-Language→defaultLocale. -
prefix: 'always'→ redirect to/{locale}/....prefix: 'as-needed'→ for the default locale, rewrite internally to/{defaultLocale}/...; otherwise redirect. A request for/{defaultLocale}/xis redirected (308) to/x, so each page has one canonical URL (#30).prefix: 'never'(v0.4) → always rewrite. - Localized
pathnames(v0.4) are mapped in both directions (/de/ueber-uns↔/de/about), using a route manifest generated fromapp/at codegen time.
Performance: codegen precomputes locale lookup tables at build time: exact tags, language/script/region parents, and the Accept-Language best-fit map. The proxy constructs no Intl.* objects per request, and caches parsed Accept-Language strings in a bounded LRU. With many locales, per-request matching in other setups has been reported at 120–180 ms for about 140 locales (r/nextjs). next-tongue's target is p50 < 1 ms with 150 locales (ROADMAP v0.2).
Cookie: TONGUE_LOCALE is set with SameSite=Lax by default so it survives cross-site navigation; see Configuration.
prefix |
URL for en (default) |
URL for de
|
Static-export friendly |
|---|---|---|---|
'always' |
/en/about |
/de/about |
✅ (the only option for output: 'export') |
'as-needed' |
/about |
/de/about |
❌ (no proxy in static export; see Static export) |
'never' |
/about |
/about (cookie/domain) |
❌ |
import { NextResponse, type NextRequest } from 'next/server';
import { createProxy } from 'next-tongue/proxy';
const tongue = createProxy();
export async function proxy(req: NextRequest) {
if (req.nextUrl.pathname.startsWith('/admin') && !req.cookies.get('session')) {
return NextResponse.redirect(new URL('/login', req.url));
}
return tongue(req);
}createProxy(options?) accepts overrides: { localeDetection?, onLocale?(locale, req) }.
import { Link, redirect, useRouter, usePathname, getPathname } from 'next-tongue/navigation';
<Link href="/about">About</Link> // → /de/ueber-uns when locale is de
<Link href="/about" locale="en">English</Link> // locale switcher
redirect({ href: '/login', locale }); // server: explicit locale, no headers read
const router = useRouter(); router.push('/about'); // client: uses TongueProvider locale
const path = usePathname(); // '/about' (locale prefix stripped)
getPathname({ href: '/about', locale: 'de' }); // '/de/ueber-uns' — for sitemaps, emailsServer-side redirect requires an explicit locale because reading it implicitly would need request headers — see Cache Components.
Add app/[locale]/not-found.tsx for localized 404s. Unknown locales should call notFound() in the root layout (isLocale helper). A global app/not-found.tsx handles requests the proxy did not match.
Guides
- Getting Started
- Configuration
- Routing and Proxy
- Server Components
- Client Components
- Server Actions
- ICU Messages
- Type Safety
- Cache Components and PPR
- Static Export
- Metadata SEO and hreflang
- Database and CMS Messages
- Dev Tools
- Translator Workflow
- Per-user Preferred Language
- CLI
- AI Translation
- Testing
- VS Code Extension
- Migration from next intl
- Migration from next international (deferred)
Reference