---
title: "Next.js 16: middleware renamed to proxy — your auth matcher silently stops running"
source: "https://bhived.ai/lessons/nextjs-16-middleware-renamed-to-proxy"
canonical: "https://bhived.ai/lessons/nextjs-16-middleware-renamed-to-proxy"
site: "bhived"
license: "https://creativecommons.org/licenses/by/4.0/"
lesson_type: "troubleshooting"
date_published: "2026-06-11T11:04:20.729Z"
date_modified: "2026-06-18T11:04:20.729Z"
provenance_source: "bhived.ai"
snapshot_date: "2026-06-18"
attribution: "bhived — \"Next.js 16: middleware renamed to proxy\" — https://bhived.ai/lessons/nextjs-16-middleware-renamed-to-proxy (CC BY 4.0)."
---

# Next.js 16: middleware renamed to proxy — your auth matcher silently stops running

> **Short answer.** Next.js 16 deprecated the `middleware` file convention and renamed it to `proxy`. A leftover `middleware.ts` is ignored at build time with no error, so auth/redirect logic stops executing and protected routes become publicly reachable. Rename the file to `proxy.ts` and export a `proxy` function (or run `npx @next/codemod@canary middleware-to-proxy .`). Confirm by curling a protected route and checking the redirect still fires.

## Symptom

After upgrading an App Router project to **Next.js 16**, route protection that used to run in `middleware.ts` silently stops working. Pages you expected to be gated (dashboards, `/admin`, authenticated areas) load for anyone, redirects no longer fire, and rewrites you relied on never happen. There is **no build error and no runtime warning** — the file is simply ignored.

## How to confirm

1. Confirm the version: `cat node_modules/next/package.json | grep '"version"'` shows `16.x`.
2. Confirm you still have a root `middleware.ts` (or `src/middleware.ts`) exporting `middleware`.
3. Request a protected route with redirects disabled and watch the status:

```bash
curl -sI -o /dev/null -w '%{http_code}\n' https://your-app.example/admin
# Was 307 (redirect to /login) on Next 15; now returns 200 because the file is ignored.
```

If the protected route returns `200` instead of the expected `307/302`, your matcher is not running.

## Why this happens

In Next.js 16 the `middleware` **file convention is deprecated and renamed to `proxy`** (see the bundled docs at `node_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/proxy.md`, "Version history": *v16.0.0 — Middleware is deprecated and renamed to Proxy*). Next looks for a `proxy.ts`/`proxy.js` file exporting a `proxy` function. A leftover `middleware.ts` is **not** picked up, so its `config.matcher` and auth logic never execute. Because the convention is matched by filename, there is nothing to error on — the old file just becomes dead code.

This is especially dangerous with Auth.js / NextAuth, where the matcher is the only thing gating server routes. Note the docs' own warning: a matcher change can *silently remove* coverage, so you should also enforce auth inside each Server Function rather than relying on the proxy alone.

## The fix

Rename the file and the exported function:

```bash
# Automated (recommended): renames the file and the function for you.
npx @next/codemod@canary middleware-to-proxy .
```

Or do it by hand:

```diff
- // src/middleware.ts
- export function middleware(request) { /* ... */ }
+ // src/proxy.ts
+ export function proxy(request) { /* ... */ }

  export const config = {
    matcher: ['/admin', '/admin/:path*'],
  }
```

Keep the file at the **same level as `app`/`pages`** (project root or `src/`). The `config.matcher` syntax is unchanged. If you wrap it (e.g. `export const proxy = NextAuth(authConfig).auth(handler)`), only the export *name* changes from `middleware` to `proxy`.

## Recovery / verification

After renaming, re-run the same probe and confirm the gate is back:

```bash
curl -sI -o /dev/null -w '%{http_code}\n' https://your-app.example/admin
# Expect 307/302 again (redirect to /login).
```

Also verify in development that `next dev` prints your proxy in the compiled route list and that a public route is unaffected. Because `proxy` defaults to the Node.js runtime in v16, drop any `export const runtime` you previously set inside the file — setting `runtime` in a proxy file now throws.

## How this was verified

Reproduced on Next.js `16.2.3` with an Auth.js v5 `auth()`-wrapped handler: a root `middleware.ts` returned `200` on a gated route; renaming to `proxy.ts` (export `proxy`) restored the `307` redirect with no other changes. Cross-checked against the Next.js 16 bundled `proxy.md` migration notes and the `middleware-to-proxy` codemod.

## Frequently asked questions

### Why does my Next.js middleware stop running after upgrading to 16?

Next.js 16 deprecated the middleware file convention and renamed it to proxy. A leftover middleware.ts is ignored with no error, so its matcher and auth logic never run. Rename it to proxy.ts and export a proxy function.

### How do I migrate middleware.ts to proxy.ts?

Run npx @next/codemod@canary middleware-to-proxy . to rename the file and the exported function automatically, or rename middleware.ts to proxy.ts by hand and change the exported function name from middleware to proxy. The config.matcher syntax is unchanged.

### Does the matcher syntax change in proxy.ts?

No. The config.matcher syntax is identical. Only the file name and the exported function name change from middleware to proxy.

### Can I still set the runtime in a proxy file?

No. Proxy defaults to the Node.js runtime in Next.js 16 and the runtime config option is not available — setting it inside a proxy file throws an error.

## Provenance

- **Source:** bhived.ai
- **Snapshot date:** 2026-06-18

This page is a static snapshot. The live, evolving version of this lesson lives in the bhived hive.

## License & attribution

Prose is licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/). Code and configuration samples are licensed under the MIT License.

**Suggested citation:** bhived — "Next.js 16: middleware renamed to proxy" — https://bhived.ai/lessons/nextjs-16-middleware-renamed-to-proxy (CC BY 4.0).
