Run code before a request finishes — redirect, rewrite, or tweak headers and cookies — using the proxy.ts file.
Why: proxy runs BEFORE a request is handled, so it can redirect, rewrite, or change headers based on the incoming request. Note: in this Next.js it lives in proxy.ts — it’s the renamed Middleware, same idea. Keep it fast; it’s not for slow data fetching.
// proxy.ts — at the project root, next to app/
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function proxy(request: NextRequest) {
return NextResponse.redirect(new URL('/home', request.url))
}Why: by default proxy runs on every request. Export a config with a matcher so it only runs where you need it — a smaller scope means less work per request. The :path* part means "this prefix and anything under it".
// proxy.ts
export const config = {
matcher: '/dashboard/:path*', // only runs under /dashboard
}Why: the most common use — gate pages on a condition (like a missing login cookie) and send the user elsewhere. For simple, static redirects, prefer the redirects() option in next.config.ts instead; reach for proxy when you need request data.
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function proxy(request: NextRequest) {
const isLoggedIn = request.cookies.has('session')
if (!isLoggedIn) {
return NextResponse.redirect(new URL('/login', request.url))
}
return NextResponse.next() // let the request continue
}Why: a rewrite serves a different page while the URL in the browser stays the same (handy for A/B tests). You can also attach headers or cookies to the response on the way through.
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function proxy(request: NextRequest) {
// Show /experiment but keep the URL the user typed
const response = NextResponse.rewrite(new URL('/experiment', request.url))
response.headers.set('x-variant', 'b')
response.cookies.set('variant', 'b')
return response
}