🟣 Data, Server & APIs · Lesson 25
Proxy (Middleware) & Redirects
What is proxy.js?
proxy.js is a single file in your project root (next to app/) whose proxy() function runs before a request reaches your pages. It can let the request continue, redirect it, rewrite it, or add headers and cookies. Before Next.js 16 this was called middleware.js.
Where it runs in the request
Example 1: redirect old URLs (EduSite)
Suppose your old site used /course/python-ai and the new one uses /courses/python-ai. Google has the old URLs indexed — a permanent redirect transfers their ranking.
JS – proxy.js
// proxy.js (project root – EduSite, complete file)
import { NextResponse } from 'next/server'
// Old URLs like /course/python-ai are permanently moved to /courses/python-ai.
export function proxy(request) {
const { pathname } = request.nextUrl
if (pathname.startsWith('/course/')) {
const url = request.nextUrl.clone()
url.pathname = pathname.replace('/course/', '/courses/')
return NextResponse.redirect(url, 308) // 308 = permanent (SEO keeps ranking)
}
return NextResponse.next() // continue normally
}
export const config = { matcher: ['/course/:path*'] }Terminal – check the redirect
$ curl -I http://localhost:3000/course/python-ai
HTTP/1.1 308 Permanent Redirect
location: /courses/python-ai
The matcher config
Without a matcher, proxy runs for every request, including images and JS files. Limit it:
JS – matcher patterns
export const config = {
matcher: [
'/dashboard/:path*', // /dashboard and everything below
'/admin/:path*',
// everything EXCEPT static files, images and API:
'/((?!api|_next/static|_next/image|favicon.ico|.*\\.png$).*)',
],
}Example 2: rewrite (maintenance page)
JS – proxy.js rewrite
// proxy.js — show a maintenance page without changing the URL
import { NextResponse } from 'next/server'
export function proxy(request) {
if (process.env.MAINTENANCE === 'on' && !request.nextUrl.pathname.startsWith('/maintenance')) {
return NextResponse.rewrite(new URL('/maintenance', request.url))
}
return NextResponse.next()
}redirect()
- Browser URL changes
- Two requests
- Use for moved pages (SEO)
rewrite()
- Browser URL stays
- One request
- Use for A/B tests, maintenance
Example 3: headers and cookies
JS – proxy.js headers
// proxy.js — add a header and remember the referral code from ?ref=
import { NextResponse } from 'next/server'
export function proxy(request) {
const res = NextResponse.next()
res.headers.set('X-Frame-Options', 'DENY') // security header
const ref = request.nextUrl.searchParams.get('ref')
if (ref) res.cookies.set('ref', ref, { maxAge: 60 * 60 * 24 * 30 }) // 30 days
return res
}Migrating from middleware.js
Terminal + JS
# Next.js provides a codemod:
npx @next/codemod@latest middleware-to-proxy .
// Before (Next.js 15) // After (Next.js 16)
// middleware.js // proxy.js
export function middleware(req) { } → export function proxy(req) { }When NOT to use proxy
- Fixed list of redirects →
redirects()in next.config is simpler. - Slow work (database queries) → proxy runs on every matched request; keep it fast.
- As the only security check → also verify in pages/actions (see Auth lesson).
Common mistakes
- Placing proxy.js inside
app/→ it must be at the project root (orsrc/). - Redirect loops (redirecting
/loginto/login) → exclude the target path. - Using 302 for permanent moves → search engines keep the old URL; use 301/308.
Summary
proxy.js+export function proxy()runs before routes.- Return
NextResponse.next(),.redirect()or.rewrite(); add headers/cookies. - Always set a
matcherand keep logic fast.
✅ Practice
Add a proxy rule that redirects /blogs/:slug to /blog/:slug with 308, and verify it with curl -I.
Frequently Asked Questions
Why was middleware renamed to proxy in Next.js 16?
To make its role clear: it sits in front of your app like a network proxy, deciding to continue, redirect or rewrite a request. The function is now export function proxy() in proxy.js.
What is the difference between redirect and rewrite?
A redirect changes the URL in the browser (the user sees the new URL). A rewrite shows content from another path while the URL stays the same.
Should I use proxy.js or next.config redirects?
For fixed old-to-new URL pairs use redirects() in next.config. Use proxy.js when the decision needs logic: cookies, headers, patterns or geography.
