What is Next.js middleware and what do you use it for?
Take a moment.
Say your answer out loud or write it down first — retrieval is what makes it stick. Reveal when you're ready.
Short answer
middleware.ts runs before every matching request at the edge — rewriting URLs, redirecting, setting headers, and gating access by cookies. It can't run heavy logic or use Node APIs; think fast routing decisions, not business logic.
Detailed explanation
A single middleware.ts at the project root exports a function receiving every incoming request (filtered by matcher config): auth gates checking session cookies before protected routes render, A/B experiments rewriting to variant pages transparently, geo/locale redirects from headers, adding security headers globally, logging. It runs in a lightweight edge runtime: Web APIs yes, heavy Node libraries no, execution time budgeted in milliseconds. Two response patterns: NextResponse.next() passes through (optionally rewriting/adding headers), redirect()/rewrite() change destination. Rewrites differ from redirects — URL stays in browser while content swaps, enabling clean experiments. Matcher config limits scope cheaply ('/dashboard/:path*'). Common mistake: treating middleware as general backend code — DB queries and sessions belong in Server Components/handlers; middleware should decide *where* requests go, quickly.
Example
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const hasSession = request.cookies.has('session');
if (!hasSession && request.nextUrl.pathname.startsWith('/dashboard')) {
const login = new URL('/login', request.url);
login.searchParams.set('from', request.nextUrl.pathname);
return NextResponse.redirect(login);
}
return NextResponse.next();
}
export const config = { matcher: ['/dashboard/:path*'] };Interview tip
List three concrete uses fast (auth gate, rewrites for experiments, header injection), then state the constraint that shapes design: edge runtime, milliseconds, no heavy compute.
Common mistakes
- Putting database calls into middleware.
- Forgetting the matcher config and running on every asset request.