`proxy.ts` in Next.js 16: What Replaced Middleware and What Changed

Next.js 16 renamed the middleware file convention to proxy. Here is the new file, the new function name, the Node.js runtime rule, and the codemod that migrates an existing project.

7 min read

proxy.ts is the Next.js 16 name for the file that earlier versions called middleware.ts. It runs on the server before a request reaches a route, and it can redirect, rewrite, adjust headers, or answer the request itself. The interception behavior is unchanged, so the migration is mostly a rename.

One change is not cosmetic. Proxy always runs on the Node.js runtime, and unlike Middleware you cannot switch it to Edge.

The file belongs at the project root, at the same level as the app directory rather than inside it. This is the smallest version of it.

typescripttypescript
// proxy.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
 
export function proxy(request: NextRequest) {
  return NextResponse.redirect(new URL('/home', request.url))
}
 
export const config = {
  matcher: '/about/:path*',
}

A request to /about/team now answers with a 307 redirect to /home before any page renders. The exported config keeps the function off every other path, which matters because a proxy file with no matcher runs on every request in the project.

What changed between middleware and proxy

Four things carry a new name in Next.js 16. Everything else, including the request and response objects, the matcher syntax, and the ability to return a response directly, works the way it did before.

Next.js 15Next.js 16
middleware.ts or middleware.jsproxy.ts or proxy.js
export function middlewareexport function proxy
Edge runtime by default, Node.js opt-inNode.js runtime only
skipMiddlewareUrlNormalizeskipProxyUrlNormalize

The old file name still runs in Next.js 16, but it is deprecated. Building a project that still uses it prints a warning that names the replacement and the codemod.

texttext
 ⚠ The "middleware" file convention is deprecated. Please use "proxy" instead.
 
  To migrate automatically, run:
  npx @next/codemod@canary middleware-to-proxy .
 
  Learn more: https://nextjs.org/docs/messages/middleware-to-proxy

Keeping the old file is only worthwhile if you depend on the Edge runtime, which the new convention does not offer. Everything else in the file continues to work unchanged.

Next.js explains the rename as a clarification of purpose. "Middleware" invited comparisons to Express, which encouraged people to treat it as a general application layer, while "proxy" describes a network boundary that sits in front of the app.

Migrating an existing project

Renaming the file and the function by hand is enough for most projects. The official codemod does both in one pass and is worth running first because it also catches a default export whose function still carries the old name.

Run the codemod

From the project root, run npx @next/codemod@canary middleware-to-proxy . and let it rewrite the file.

Rename the renamed config flags

Search the Next.js config for any option that contains the word middleware and switch it to the proxy spelling.

Check the runtime assumption

Remove any runtime export from the file, and confirm nothing in it depends on Edge-only behavior.

Verify a matched route

Request a path that the matcher covers and confirm the redirect, rewrite, or header still appears.

The codemod renames both the file and the exported function, so a project that only used the standard shape needs no further edits. The Next.js 16 upgrade codemod runs this migration as part of the larger upgrade.

If you split proxy logic across helper modules, only the entry file needs the new name. Next.js still supports exactly one proxy file per project, and imports into it are unaffected.

The Node.js runtime rule

Middleware ran on the Edge runtime by default and gained stable Node.js support in Next.js 15.5. Proxy inverts that: Node.js is the only option, and the route segment runtime option is not available in the file.

Exporting one anyway is never silently ignored. next build fails with the message below, and next dev logs the same text once and then runs the file on Node.js regardless.

texttext
Route segment config is not allowed in Proxy file at "./proxy.ts". Proxy always runs on Node.js runtime. Learn more: https://nextjs.org/docs/messages/middleware-to-proxy

That removes a class of surprises. Node built-ins, database drivers, and libraries that were awkward or impossible under Edge constraints now work in the same place as the rest of your server code.

Edge users should not rename yet

If a project genuinely needs the Edge runtime for request interception, keep the deprecated middleware file. The proxy convention does not support Edge, and Next.js has said it will publish further Edge guidance in a later minor release.

Static exports are the other limitation to know. A Node.js server and a Docker container both run Proxy, but a fully static export has no server to run it on, so the file is ignored there.

Where Proxy sits in the request pipeline

Proxy is not the first thing that touches a request. Headers and redirects declared in the Next.js config are applied before it, and filesystem routes are resolved after it. Knowing that order explains most surprising results.

Order of routing steps around Proxy

A redirect declared in the config wins over Proxy for the same path, because it is applied first and the request never reaches the function. That is usually the right outcome, and it is why a config redirect is the better tool for a fixed old-to-new path mapping.

Server Functions are worth calling out here. They are not separate routes: a Server Action posts to the route it was used on, so a matcher that excludes that path also skips Proxy for the action.

What Proxy is not for

Proxy runs before every matched request, so slow work there slows down the whole site. Data fetching options such as the fetch cache and revalidation settings have no effect inside it, which is a strong hint about its intended scope.

Authorization is the other misuse. A redirect from Proxy is an optimistic check that improves the experience for a signed-out visitor, but it is not a security boundary, and a refactor that changes the matcher can silently remove it.

The durable rule is that every Server Action and Route Handler authorizes itself. Securing Server Actions covers the checks that belong inside the action rather than in front of it.

When to reach for Proxy

Reach for Proxy when the routing decision depends on the incoming request and cannot be expressed in configuration. Reading a cookie to choose an experiment, branching on a header, or rewriting to a region-specific page all qualify.

Prefer a config redirect or rewrite for static path mappings, and prefer a Server Component or Route Handler when the work involves real data. Those run once per matched route instead of in front of everything.

Three habits keep a proxy file healthy as a project grows. Give it a matcher immediately, so it never runs against static assets and image requests. Keep the function synchronous where you can, since anything awaited there is added to the time before the page starts rendering.

The third habit is verification. A proxy file that silently stops matching looks exactly like a proxy file that was never written, so check a covered path in the browser network panel after any matcher edit and confirm the status code you expect.

Rune AI

Rune AI

Key Insights

  • Next.js 16 renamed the middleware file convention to proxy, and the old names are deprecated.
  • The file lives at the project root next to app, and it exports one function named proxy.
  • Proxy always runs on the Node.js runtime, and that runtime cannot be configured.
  • Config flags carrying the middleware name were renamed, such as skipProxyUrlNormalize.
  • The middleware-to-proxy codemod renames the file and the exported function for you.
RunePowered by Rune AI

Frequently Asked Questions

Does middleware.ts still work in Next.js 16?

Yes, but it is deprecated. Next.js still runs a middleware file and its middleware export, and it warns that the convention has been renamed. The one reason to stay on the old file is the Edge runtime, which the proxy convention does not support.

Can I set the runtime for proxy?

No. Proxy always uses the Node.js runtime, and the route segment runtime option is not available in a proxy file. Setting it throws an error at build time.

Can a project have more than one proxy file?

No. Next.js supports a single proxy file at the project root, or inside src when you use that layout. You can still split the logic into modules and import them into that one file.

Is proxy a replacement for authentication?

No. Proxy is useful for optimistic checks such as sending a signed-out visitor to a login page, but the real session and permission checks belong in the page, Server Action, or Route Handler that touches the data.

Conclusion

Proxy is the Next.js 16 name for the middleware file convention. Move the file to proxy.ts, rename the exported function to proxy, drop any Edge runtime assumption, and rename the config flags that carried the old name. The request-interception behavior itself did not change.