Capítulo 372 de 456
proxy.js|ts (the renamed middleware.js) runs code on the server before a request completes, letting you rewrite, redirect, or modify requests/responses ahead of routing, e.g. for auth or logging.
proxy function: default or named export proxy(request, event); only one per file, runs on every route unless scoped by matcher.matcher: exported config.matcher (string, array, or array of objects with source/locale/has/missing) restricting which paths trigger the proxy; must be statically analyzable (no dynamic variables).request (NextRequest): first param, the incoming HTTP request.event (NextFetchEvent): second param, exposes waitUntil(promise) to extend proxy lifetime for background work.NextProxy type: shorthand type inferring both request and event param types.next.config.js headers → next.config.js redirects → Proxy → beforeFiles rewrites → filesystem routes → afterFiles rewrites → dynamic routes → fallback rewrites.runtime file-convention config option cannot be used in Proxy files (throws an error).skipTrailingSlashRedirect / skipProxyUrlNormalize: next.config.js flags for advanced trailing-slash and URL-normalization control inside proxy logic.unstable_doesProxyMatch: from next/experimental/testing/server (Next.js 15.1+), unit-tests whether proxy matches a given URL/headers/cookies without running it.import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function proxy(request: NextRequest) {
return NextResponse.redirect(new URL('/home', request.url))
}
export const config = {
matcher: '/about/:path*',
}
export const config = {
matcher: [
'/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)',
],
}
export function proxy(req: NextRequest, event: NextFetchEvent) {
event.waitUntil(
fetch('https://my-analytics-platform.com', {
method: 'POST',
body: JSON.stringify({ pathname: req.nextUrl.pathname }),
})
)
return NextResponse.next()
}
waitUntil keeping proxy alive for background logging after the response is sent.| Matcher object key | Purpose |
|---|---|
source | path/pattern to match (must start with /) |
locale | false ignores locale-based routing |
has | run only if header/query/cookie is present |
missing | run only if header/query/cookie is absent |
| Deployment | Supported |
|---|---|
| Node.js server | Yes |
| Docker container | Yes |
| Static export | No |
| Adapters | Platform-specific |
matcher: proxy runs on every request including static files and images, potentially blocking CSS/JS/image loads with auth logic.NextResponse.next({ headers }): exposes them to the client and can override framework-critical headers like Content-Type; forward request headers only via NextResponse.next({ request: { headers } })._next/data in matcher expecting it to skip proxy: Next.js still invokes proxy for _next/data routes intentionally, to avoid protecting a page but forgetting its data route.middleware convention (renamed in v16.0.0); a codemod (npx @next/codemod@canary middleware-to-proxy .) automates migration.matcher patterns, not a global catch-all, to avoid unintended blocking or overhead.NextResponse.rewrite() auto-propagates RSC headers; custom fetch()-based rewrites need skipProxyUrlNormalize and manual header forwarding.runtime config.unstable_doesProxyMatch, isRewrite, and getRewrittenUrl from next/experimental/testing/server.request param's full API (cookies, nextUrl).redirect, rewrite, next, json, cookie methods used to produce proxy responses.as/href.