| name | migrating-middleware-to-proxy |
| description | Teach middleware.ts to proxy.ts migration in Next.js 16. Use when migrating middleware, encountering middleware errors, or implementing request proxying. |
| allowed-tools | Read, Write, Edit, Glob, TodoWrite |
| version | 1.0.0 |
MIGRATION: middleware.ts to proxy.ts
Overview
Next.js 16 renames middleware.ts to proxy.ts and the middleware export to proxy. This is a breaking change with security implications (CVE-2025-29927).
Why This Change Matters
CVE-2025-29927: Middleware-based authentication is fundamentally broken in Next.js. Middleware cannot reliably protect routes because:
- Middleware runs at the edge, but authentication state lives in databases/sessions
- Race conditions between middleware checks and route handlers
- Middleware can be bypassed through direct route access
- Edge runtime limitations prevent proper session verification
The rename to "proxy" clarifies that this API is for request/response manipulation, not security.
Migration Steps
1. Rename the File
# Old location
src/middleware.ts
# New location
src/proxy.ts
2. Rename the Export
Before (Next.js 15):
export function middleware(request: NextRequest) {
return NextResponse.next();
}
export const config = {
matcher: ['/api/:path*', '/dashboard/:path*'],
};
After (Next.js 16):
export function proxy(request: NextRequest) {
return NextResponse.next();
}
export const config = {
matcher: ['/api/:path*', '/dashboard/:path*'],
};
3. Update Configuration
If using next.config.js or next.config.ts:
const nextConfig = {
experimental: {
},
};
No configuration changes needed for proxy. The framework detects proxy.ts automatically.
Security Migration
If you were using middleware for authentication, you must migrate to route-level protection.
Before (Insecure)
export function middleware(request: NextRequest) {
const token = request.cookies.get('auth-token');
if (!token) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.next();
}
export const config = {
matcher: ['/dashboard/:path*'],
};
After (Secure)
proxy.ts:
export function proxy(request: NextRequest) {
const response = NextResponse.next();
response.headers.set('x-custom-header', 'value');
return response;
}
app/dashboard/layout.tsx:
import { redirect } from 'next/navigation';
import { verifySession } from '@/lib/auth';
export default async function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
const session = await verifySession();
if (!session) {
redirect('/login');
}
return <>{children}</>;
}
Key differences:
- Authentication logic moves to Server Components
- Session verification happens in the same runtime as data access
- No race conditions between auth check and data fetch
- Can access database/session store reliably
Valid Use Cases for proxy.ts
Use proxy.ts for:
Request/response header manipulation
export function proxy(request: NextRequest) { const response = NextResponse.next(); response.headers.set('x-frame-options', 'DENY'); return response; }Request logging/monitoring
export function proxy(request: NextRequest) { console.log(`${request.method} ${request.url}`); return NextResponse.next(); }URL rewriting
export function proxy(request: NextRequest) { if (request.nextUrl.pathname === '/old-path') { return NextResponse.rewrite(new URL('/new-path', request.url)); } return NextResponse.next(); }Geolocation routing
export function proxy(request: NextRequest) { const country = request.geo?.country; if (country === 'US') { return NextResponse.rewrite(new URL('/us', request.url)); } return NextResponse.next(); }
Do NOT Use proxy.ts For
- Authentication/authorization checks
- Session validation
- Database queries
- Complex business logic
- Rate limiting (use route handlers instead)
Migration Checklist
- Rename
middleware.tstoproxy.ts - Rename
middlewareexport toproxy - Remove authentication logic from proxy
- Move authentication to Server Components/Route Handlers
- Test that routes are properly protected
- Verify edge cases (direct route access, API routes, etc.)
- Update tests that reference middleware
Common Errors
Error: "middleware is not exported"
You forgot to rename the export from middleware to proxy.
Error: "proxy is not a function"
Ensure you're exporting a function named proxy, not a default export.
Error: "Cannot access database in proxy"
Proxy runs at the edge runtime. Move database access to route handlers or Server Components.
Additional Resources
- CVE-2025-29927: Next.js Middleware Authentication Vulnerability
- Next.js 16 Migration Guide: Proxy API
- Next.js Security Best Practices: Route-Level Protection