Next.js 16 App router internationalization root error
07:29 05 Dec 2025

After following the guide on: https://nextjs.org/docs/app/guides/internationalization The translation logic itself seems to work, but the redirection from the root will never happen.

When visiting localhost:3000 (localhost:3000/) it will always end up giving back a 404 error. Visiting localhost:3000/en correctly gives back the english version of the root page, and visiting localhost:3000/de correctly gives back the german version.

If i understand this correctly the problem must be caused by the proxy that is not redirecting correctly but after spending a lot of time on changing things and even trying to explicitly handle pathname === "/" I still cant make it work, changing the matcher to multiple different suggestions also didnt work.

Regarding the project structure, everything is moved under app/[lang]/ as per guide. So the root page also lives under app/[lang]/page.tsx as well as root layout app/[lang]/layout.tsx

I am stuck with this and would appreciate any help and a possible explanation of as why the root is not redirected to the default locale language. (e.g localhost:3000 => should redirect to localhost:3000/de in my case since de is specified as default)

This is my current proxy.ts (which is almost identical to the guide):

import { NextResponse } from "next/server";
import { match } from "@formatjs/intl-localematcher";
import Negotiator from "negotiator";

const locales = ["de", "en"];
const defaultLocale = "de";

function getLocale(request: Request) {
  const negotiatorHeaders: Record = {};
  request.headers.forEach((value, key) => (negotiatorHeaders[key] = value));

  const languages = new Negotiator({ headers: negotiatorHeaders }).languages();
  return match(languages, locales, defaultLocale);
}

export function proxy(request: any) {
  const { pathname } = request.nextUrl;

  if (
    locales.some(
      (loc) => pathname === `/${loc}` || pathname.startsWith(`/${loc}/`),
    )
  ) {
    return;
  }

  const locale = getLocale(request);

  request.nextUrl.pathname = `/${locale}${pathname}`;
  return NextResponse.redirect(request.nextUrl);
}

export const config = {
  matcher: [
    // Skip all internal paths (_next)
    "/((?!_next).*)",
    // Optional: only run on root (/) URL
    // '/'
  ],
};
typescript next.js routes internationalization app-router