Proxy (formerly Middleware)
Running code before a request completes to redirect, rewrite, or inspect it — and why it's now called Proxy.
阅读需 3 分钟
Some logic needs to run before any route in your app even starts rendering — checking whether a visitor is logged in and redirecting them, rewriting a request to a different path based on an A/B test, or adding a header to every response. If you've used an older Next.js tutorial, you'll know this feature as Middleware. As of Next.js 16, it's been renamed to Proxy to better describe what it actually does — the underlying functionality hasn't changed, only the name and the file you create.
The proxy.ts convention
Create a proxy.ts file at the root of your project (next to app/, or inside src/ if you use that layout). Unlike routes, there's only ever one of these per project:
// proxy.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export function proxy(request: NextRequest) {
const isLoggedIn = request.cookies.has("session");
if (!isLoggedIn && request.nextUrl.pathname.startsWith("/dashboard")) {
return NextResponse.redirect(new URL("/login", request.url));
}
return NextResponse.next();
}
export const config = {
matcher: "/dashboard/:path*",
};This runs before the /dashboard/* routes even begin rendering. If there's no session cookie, the visitor is redirected to /login before any of the dashboard's own code — data fetching, layouts, anything — ever executes.
Scoping it with matcher
Without a matcher, a proxy function runs on every request to your app, which is rarely what you want. The config.matcher export restricts it to specific paths, using the same pattern syntax as dynamic routes:
export const config = {
matcher: ["/dashboard/:path*", "/settings/:path*"],
};What it's good for
- Redirecting based on something only known at request time — an auth cookie, a geolocation header, an A/B test bucket
- Rewriting a request to a different internal path without the browser's URL changing
- Adding or modifying response headers across many routes at once (a security header, for instance)
What it's explicitly not for
Proxy is not intended for slow work. It runs on every matched request, so anything expensive there — a database query, a slow third-party API call — adds latency to every single page load it applies to. It's also not a substitute for real session management: using it for a quick "does a cookie exist" redirect (an optimistic check) is reasonable, but the actual authorization decision — verifying that cookie is valid, checking permissions — belongs in your Server Components, Server Actions, and Route Handlers, not solely in Proxy.
One more sharp edge worth knowing: fetch caching options (cache, next.revalidate, next.tags) have no effect when called from inside a proxy function — requests made there always run fresh, every time.
If you're reading older tutorials
Plenty of existing guides, Stack Overflow answers, and even AI-generated code still say "Middleware" and use a middleware.ts filename — that was accurate for every Next.js version before 16. The concept transfers directly; only the file's name and the exported function's name changed. If a middleware.ts file isn't being picked up in a current project, this rename is almost always why.