Teach middleware.ts to proxy.ts migration in Next.js 16. Use when migrating middleware, encountering middleware errors, or implementing request proxying.
Migrates Next.js middleware.ts to proxy.ts, fixing CVE-2025-29927 authentication vulnerabilities.
/plugin marketplace add djankies/claude-configs/plugin install nextjs-16@claude-configsThis skill is limited to using the following tools:
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).
CVE-2025-29927: Middleware-based authentication is fundamentally broken in Next.js. Middleware cannot reliably protect routes because:
The rename to "proxy" clarifies that this API is for request/response manipulation, not security.
# Old location
src/middleware.ts
# New location
src/proxy.ts
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*'],
};
If using next.config.js or next.config.ts:
const nextConfig = {
experimental: {
},
};
No configuration changes needed for proxy. The framework detects proxy.ts automatically.
If you were using middleware for authentication, you must migrate to route-level protection.
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*'],
};
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:
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();
}
middleware.ts to proxy.tsmiddleware export to proxyError: "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.