Next.js 16: How to Migrate middleware.ts to proxy.ts (And Fix That Vercel Warning)
Author
Muhammad Awais
Published
May 30, 2026
Reading Time
12 min read
Views
15k

That Vercel Warning After Upgrading to Next.js 16 - Here's What It Means
You upgraded to Next.js 16, deployed to Vercel, and got this in your build logs:
WARNING: Unable to find source file for page middleware with extensions: tsx, ts, jsx, js, this can cause functions config from vercel.json to not be appliedYour app still deployed. It still works. But something is clearly wrong, and ignoring a warning about middleware not being found is not a great idea when middleware is what's protecting your auth routes. What happened is straightforward: Next.js 16 renamed middleware.ts to proxy.ts. Your old file is still sitting there under the old name, and the framework can't find it anymore.
This guide covers exactly why the rename happened, the fastest way to migrate, how to fix the Vercel warning properly, and the handful of errors that catch developers off guard after the migration is "done."
Why Next.js 16 deprecated
middleware.tsand renamed it toproxy.tsTwo ways to migrate automated codemod and manual with the exact commands
Why the Vercel warning appears even after renaming and how to fully resolve it
API and config changes between
middleware.tsandproxy.ts5 common post-migration errors and their fixes
Why Next.js 16 Renamed middleware.ts to proxy.ts
The rename isn't cosmetic. The Vercel team made this change because the word "middleware" had become overloaded it means different things in Express, in HTTP standards, and in the Next.js context. What Next.js actually does is closer to a proxy: it intercepts requests before they reach your application, optionally rewrites or redirects them, and forwards them along. That's proxy behavior, not generic middleware behavior.
The practical implication is that the API surface is essentially the same. NextRequest, NextResponse, matchers, edge runtime declarations none of that changed. What changed is the filename and how Next.js discovers and registers the file at build time.
There's also a security angle here. Several of the 13 vulnerabilities patched in the May 2026 Next.js security release were specifically in the middleware/proxy layer bypass issues that the team addressed alongside the rename. Running Next.js 16 with an undetected proxy file (because it's still named middleware.ts) means those protections aren't active.
The Fastest Way: Run the Official Codemod
Next.js ships a codemod that handles the rename automatically. For most projects, this is a one-command migration:
npx @next/codemod@latest rename-middleware-to-proxy .The codemod does three things:
Renames
middleware.ts(ormiddleware.js) toproxy.tsin your project rootUpdates any import references that explicitly reference the middleware file path
Updates the
next.config.jsornext.config.tsif you have middleware-specific config defined there
After running it, commit the changes, push, and your Vercel warning should be gone. For most standard setups auth middleware that checks cookies or JWTs, redirects for locale detection, A/B testing header injection the codemod handles everything and you're done in under 2 minutes.
If you're still seeing the warning after running the codemod, the next section covers why.
Why the Vercel Warning Persists Even After Renaming
This is where most teams get stuck. They rename the file (or run the codemod), redeploy, and the same warning is still there. Three common reasons:
1. The file is not in the project root
proxy.ts must live in the root of your project the same level as package.json. Not inside src/, not inside app/, not inside lib/. If you had src/middleware.ts before, it needs to become src/proxy.ts and then you also need to configure the proxyDir in next.config.ts to tell Next.js where to find it:
// next.config.ts
const nextConfig = {
proxyDir: './src',
}
export default nextConfig2. vercel.json still references "middleware"
If your vercel.json has a functions config that references middleware paths, it needs updating. The warning text specifically mentions "functions config from vercel.json to not be applied" that's the exact issue. Update any path references from middleware to proxy:
// vercel.json — before
{
"functions": {
"middleware": {
"maxDuration": 10
}
}
}
// vercel.json — after
{
"functions": {
"proxy": {
"maxDuration": 10
}
}
}3. Build cache is serving the old file
Vercel caches build artifacts aggressively. After renaming, trigger a fresh deployment with cache cleared. In the Vercel dashboard: Settings → Functions → Clear Build Cache, then redeploy. Or add --force if deploying via CLI:
vercel --prod --forceManual Migration - When the Codemod Isn't Enough
For complex projects with custom middleware factory patterns, dynamic imports, or test files that reference middleware internals, the codemod sometimes misses things. Here's the complete manual checklist:
Rename the file.
middleware.ts→proxy.tsat your project root (orsrc/if configured).Update the export name - but only if you changed it. The function can still be called
middlewareinternally. What matters is the filename, not the export name. This is a common misconception you don't need to rename the function inside the file.Check your
export const configblock. If you have a config export with a matcher array, it's unchanged:export const config = { matcher: ['/dashboard/:path*', '/api/protected/:path*'], }This syntax is identical in both
middleware.tsandproxy.ts.Update test file imports. If you have unit tests that import from
middleware, update those import paths:// Before import { middleware } from '../middleware' // After import { middleware } from '../proxy'Update any barrel exports. If your
index.tsre-exports from middleware, update the source path.Update
vercel.jsonas described in the previous section.
What Changed in the proxy.ts API - and What Didn't
The short version: almost nothing changed in the actual API. Here's the breakdown:
Feature | middleware.ts (Next.js 15) | proxy.ts (Next.js 16) |
|---|---|---|
Import source |
|
|
Request object |
|
|
Response object |
|
|
Matcher config |
|
|
Edge runtime |
|
|
File discovery | Looks for | Looks for |
vercel.json key |
|
|
If you're using JWT verification inside your proxy file, the logic is identical. Our free JWT Decoder tool can help you inspect and verify tokens during testing paste the JWT from your cookie or header and check the claims without writing debug code.
5 Common Errors After Migration - And Their Fixes
These are the issues I've seen come up repeatedly across different projects after the rename.
Error 1: Auth stops working on protected routes
Symptom: After renaming, your protected routes are suddenly accessible without authentication.
Cause: The proxy file isn't being detected. Next.js silently skips proxy execution if the file isn't found it doesn't throw an error, it just runs without any proxy logic.
Fix: Verify the file is in the correct location (./proxy.ts at project root or your configured proxyDir). Run npx next build locally and check the output for "proxy" in the route summary. If it's not listed, the file isn't being picked up.
Error 2: TypeScript can't find the module after renaming
Symptom: Cannot find module '../middleware' errors in your test suite or other files.
Fix: Update all import paths referencing middleware to proxy. Run a global search in your project: search for from '../middleware' and from './middleware' and update each one.
Error 3: Redirects from proxy.ts not working
Symptom: NextResponse.redirect() calls that worked in middleware.ts now do nothing or loop.
Cause: Usually a matcher configuration issue if your matcher pattern doesn't match the incoming request path, proxy.ts never runs for that route.
Fix: Add a console.log(request.nextUrl.pathname) temporarily to verify which paths are hitting proxy.ts. Check your matcher against the actual paths being requested. Remember that the matcher runs against the pathname without query strings.
Error 4: Edge runtime declaration error on deploy
Symptom: Build error mentioning edge runtime incompatibility after migration.
Cause: This is usually pre-existing a library used inside proxy.ts that doesn't support the edge runtime. The rename surfaces it because the build now correctly discovers the file.
Fix: Remove the export const runtime = 'edge' declaration if you're using Node.js-only packages inside proxy.ts, or replace the incompatible package with an edge-compatible alternative.
Error 5: vercel.json functions config silently ignored
Symptom: Custom function timeouts or memory settings from vercel.json aren't applying to your proxy function.
Fix: Update the key in your vercel.json functions object from "middleware" to "proxy" as shown earlier. This is silent no error, the old config just doesn't apply.
Testing Your proxy.ts is Actually Running
Don't trust that the rename worked verify it. Here's a reliable test:
Add a temporary response header inside
proxy.ts:export function middleware(request) { const response = NextResponse.next() response.headers.set('x-proxy-active', 'true') return response }Deploy and open your browser DevTools → Network tab.
Load any page that matches your proxy matcher.
Check the response headers for
x-proxy-active: true.
If the header is present, proxy.ts is running. If not, the file isn't being detected. Remove the test header before your final deployment.
For auth-specific testing, check that protected routes return the correct redirect or 401 response for unauthenticated requests. Our guide on securing Server Actions in Next.js covers the auth patterns that work well alongside proxy.ts.
One More Thing - Update Your Documentation and Team
The rename is a breaking change that affects everyone on your team who touches the repo. Update your internal docs, README setup instructions, and any architecture diagrams that reference middleware.ts. If you have onboarding docs that say "auth logic lives in middleware.ts", update them.
It's also worth adding a comment at the top of proxy.ts for context:
/**
* proxy.ts — Next.js 16+ (previously middleware.ts in Next.js 15 and earlier)
* Handles auth verification, locale detection, and request rewrites.
* See: https://nextjs.org/docs/app/building-your-application/routing/middleware
*/New team members will inevitably search for "middleware" in the codebase and not find it. The comment prevents 20 minutes of confusion.
If you're also navigating the broader Next.js upgrade from Pages Router to App Router, our complete App Router migration guide for 2026 covers the full picture including layouts, data fetching changes, and everything that broke in the process.
Frequently Asked Questions
What is proxy.ts in Next.js 16?
proxy.ts is the new name for what was previously middleware.ts in Next.js 15 and earlier. It serves the same purpose: intercepting incoming requests before they reach your application to run auth checks, redirects, rewrites, locale detection, or custom headers. The rename in Next.js 16 better reflects what the file actually does it acts as a proxy layer between incoming HTTP requests and your application routes. The API inside the file is identical.
Do I need to rename my middleware function to "proxy" inside the file?
No. The function exported from proxy.ts can still be named middleware Next.js doesn't care about the function name, only the filename. The codemod won't rename your exported function either. Only the filename itself needs to change from middleware.ts to proxy.ts.
Why does the Vercel warning say my middleware can't be found even after renaming?
Three common causes: the renamed file is not in the correct location (it must be at project root or your configured proxyDir), your vercel.json still references the old "middleware" key in the functions config, or Vercel's build cache is serving the previous deployment. Clear the build cache in your Vercel project settings and redeploy. If the warning persists, check that proxy.ts is at the root level alongside package.json.
Is middleware.ts completely removed in Next.js 16 or just deprecated?
As of Next.js 16.2.4 (the current stable release as of May 2026), middleware.ts is deprecated meaning Next.js no longer looks for it by default, which is what causes the Vercel warning. It's not a hard error; your app won't fail to build. But the proxy file won't run, so any auth or routing logic in it is silently skipped. Treat it as effectively removed the file being present doesn't help you.
Does the middleware.ts to proxy.ts rename affect the matcher configuration?
No. The export const config block with the matcher array is identical in both versions. Your existing matcher patterns work exactly the same in proxy.ts without any modification. The codemod preserves this config block unchanged.
Can I use proxy.ts with the Pages Router or only the App Router?
proxy.ts works with both the App Router and the Pages Router just like middleware.ts did before it. The file runs at the edge before your router handles the request, regardless of which routing system your Next.js app uses. If you're still on Pages Router and planning to migrate, our App Router migration guide covers that transition in detail.
Continue Reading
View All HubLevel Up Your Workflow
Free professional tools mentioned in this article
Cron Job Expression Generator & Explainer
Generate cron expressions visually and instantly translate any cron schedule into plain English. Includes GitHub Actions, Vercel, and AWS presets.
HTML to JSX / TSX Converter
Instantly convert HTML code to React JSX or TSX components. Automatically handles className, style objects, SVGs, and self-closing tags with secure, in-browser processing.
Bcrypt Generator & Verifier
Generate and verify Bcrypt password hashes instantly in your browser. A secure, client-side Bcrypt hash calculator for developers with zero backend logs.
Regex Tester & Debugger
Test, debug, and validate JavaScript regular expressions instantly. Live match highlighting, capture groups, all flags supported - free, client-side, zero logs.




