Skip to content
C.W.K.
Stream
Lesson 02 of 09 · published

Proxy (formerly Middleware)

~22 min · proxy, middleware, Node runtime

Level 0Curious
0 XP0/68 lessons0/11 achievements
0/120 XP to next level120 XP to go0% complete

The big rename

In Next.js 16, middleware.ts was renamed to proxy.ts, and the exported function changed from middleware() to proxy(). The default runtime also moved from Edge to Node.js (since v15.5).

Where it lives

proxy.ts sits at the project root, next to app/. It runs on every request that matches the matcher config — before the route renders.

Why the rename

The old name suggested it was "in the middle of React rendering." It isn't — it sits between the network and the route, like a reverse proxy. The new name reflects that. The codemod renames it for you.

Keep proxy.ts narrowly focused on request-time routing decisions that must happen before a route renders: coarse redirects, locale selection, or inexpensive admission checks. Write a precise matcher, exclude static assets, and keep authorization in the data or mutation layer as well. Renaming Middleware to Proxy is a clue about its role, not permission to move business logic into a universal request hook. Database-heavy work and final authorization there increase latency and still leave direct server calls needing their own checks. List the URLs that should and should not invoke the proxy, then test both groups including assets, API paths, and prefetches. Record the redirect or rewrite and confirm a direct call to protected data remains denied without relying on the proxy.

Code

proxy.ts at the project root·ts
// proxy.ts
import { NextRequest, NextResponse } from 'next/server';

export function proxy(request: NextRequest) {
  const session = request.cookies.get('session')?.value;
  if (!session && request.nextUrl.pathname.startsWith('/dashboard')) {
    return NextResponse.redirect(new URL('/login', request.url));
  }
  return NextResponse.next();
}

export const config = {
  matcher: ['/dashboard/:path*', '/api/:path*'],
};
Matcher patterns·ts
export const config = {
  matcher: [
    '/dashboard/:path*',
    '/api/:path*',
    // Skip static and image assets
    '/((?!_next/static|_next/image|favicon.ico).*)',
  ],
};

External links

Exercise

Migrate an existing middleware.ts to proxy.ts using the codemod. Confirm the same matcher rules still apply.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.