Middleware is the code that runs before every matched request hits your route. In Next.js, you define it in a single file at the project root (middleware.ts or, in Next.js 16, proxy.ts) and it intercepts requests at the network edge. You get access to cookies, headers, the URL, and geolocation data. You can redirect, rewrite, set headers, or return a response directly -- all before your page or API route renders a single byte.
The mental model is straightforward: middleware is a function that receives a NextRequest and must return a NextResponse. Every millisecond you spend here is added to every matched request, so the rule is simple -- keep it fast, keep it thin. Auth checks, locale detection, feature flags, CORS headers. Not database queries, not heavy computation.
Master next.js middleware
Take the Next.js Full-Stack course with hands-on lessons and challenges.
Check for a session cookie on protected routes. If missing, redirect to login with a `from` param so the login page can bounce the user back after authentication. The matcher ensures this only runs on routes that actually need protection -- not on images, fonts, or public pages.
Detects the user's preferred locale from a cookie or the Accept-Language header, then rewrites the URL so the correct localized content is served. The browser URL stays clean (/about instead of /en/about). The negative lookahead matcher excludes API routes and static assets.
Assigns users to an A/B test variant via cookie. First-time visitors get randomly bucketed; returning visitors see the same variant. The rewrite is invisible -- the user always sees /pricing in their browser while the server renders the variant-specific page.
Handles CORS at the middleware layer so every API route gets consistent headers without duplicating logic. Preflight (OPTIONS) requests get a 204 with the right headers. Actual requests get the Allow-Origin header attached. Only whitelisted origins are permitted.
Extracts the subdomain from the Host header and rewrites the URL to a tenant-specific folder. The user sees acme.myapp.com/pricing but the server renders the page at /tenants/acme/pricing. This is the foundation of multi-tenant SaaS routing without deploying separate apps per customer.
Adds security headers and a unique request ID to every response. The request ID flows through to your logging infrastructure, making it possible to trace a single user request across server components, API routes, and external services. Security headers are set once in middleware instead of repeated in every route.
Not setting a matcher -- middleware runs on every request including images, fonts, CSS, and internal Next.js routes, adding latency to everything
Always export a `config.matcher`. At minimum, exclude static assets with the negative lookahead pattern: `'/((?!_next/static|_next/image|favicon.ico).*)'`. Better yet, list only the specific paths that need middleware.
Making database calls or heavy async operations inside middleware, turning every page load into a waterfall
Middleware runs on every matched request. Verify JWTs with a lightweight library like `jose` (just a signature check). If you need to hit a database, do it in a Server Component or Route Handler where caching and streaming can absorb the latency.
Creating redirect loops by redirecting to a path that is itself matched by the middleware (e.g., protecting `/login` while redirecting unauthenticated users to `/login`)
Either exclude redirect destinations from your matcher, or add an early return for public paths like `/login`, `/signup`, and `/forgot-password` before running any auth logic.
Treating middleware as the sole security layer -- assuming that because middleware blocks unauthenticated users, Server Components and API routes don't need their own checks
Middleware is a UX optimization (fast redirects), not a security guarantee. Always re-validate authentication in Server Components and Server Actions, close to where data is accessed. Middleware can be bypassed through direct API calls or internal rewrites.
Next.js middleware (renamed to proxy in Next.js 16, though the file can still be `middleware.ts`) intercepts requests before they reach your routes. Use it for auth redirects, locale detection, A/B testing, CORS, multi-tenant rewrites, and security headers. The core API is `NextRequest` (cookies, headers, URL) in and `NextResponse` (next, redirect, rewrite, json) out. Always configure a matcher to avoid running on static assets, keep the function fast, and never rely on middleware as your only security layer -- validate auth again in Server Components and route handlers.
Interactive lessons and challenges on Stanza, practice in VS Code, Cursor, or the web.
Interactive lessons and challenges, right in your code editor.
Check the free courses. No credit card.