8. Bonus: Middleware for i18n (Internationalization)
Protection isn't the only use case. Middleware is perfect for Language Routing.
You can detect the user's Accept-Language header and redirect them to /ko or /en.
/* middleware.ts */
import { match } from '@formatjs/intl-localematcher';
import Negotiator from 'negotiator';
// 1. Define supported locales
let locales = ['en', 'ko', 'ja'];
let defaultLocale = 'en';
export function middleware(request) {
const pathname = request.nextUrl.pathname;
// 2. Check if path already has locale
const pathnameIsMissingLocale = locales.every(
(locale) => !pathname.startsWith(`/${locale}/`) && pathname !== `/${locale}`
);
// 3. Redirect if missing
if (pathnameIsMissingLocale) {
let languages = new Negotiator({ headers: request.headers }).languages();
let locale = match(languages, locales, defaultLocale);
return NextResponse.redirect(
new URL(`/${locale}${pathname}`, request.url)
);
}
}
This logic runs before the page loads, ensuring the user always lands on the correct language version without a flash.
By leveraging Middleware for both security and routing, you create a robust, performant application architecture that is secure by default. It separates concerns effectively: pages handle rendering, and middleware handles access control.
A Note on Cold Starts
Since Middleware runs on the Edge, it generally has negligible cold starts compared to Serverless functions (AWS Lambda).
However, if you import heavy libraries (which you shouldn't), you might introduce latency.
Keep your middleware lightweight. If you need complex logic, offload it to an API route and just call it from the middleware (though be careful with latency there too).
The golden rule is: Middleware should be fast. It runs on every single request.