Next.js 16 Proxy Triggering Node Runtime for Every Page — Function Quota Drain on Vercel
Unanswered
valse posted this in #help-forum
valseOP
Hi everyone — I’m facing a major issue after upgrading from Next.js 15 to 16, and I’m hoping someone can shed light on it or offer a workaround.
I use middleware to handle i18n redirects across my app. In Next.js 15, this middleware ran efficiently on Vercel — it didn’t consume my function invocation quota for every page request. The logs showed edge runtime behavior, and everything was smooth.
After upgrading to Next.js 16, I noticed that every page request now triggers a Node.js runtime invocation for the middleware. The Vercel logs show for each request, and my function quota is draining rapidly.
From what I understand, this is due to the new proxy architecture in Next.js 16, which routes middleware through the Node runtime. While this may enable more advanced features, it’s a huge problem for apps like mine that rely on global middleware for routing.
What I’ve observed:
• Middleware is invoked for every page request.
• Vercel logs show Node runtime () instead of edge.
• Function invocation quota is being consumed aggressively.
• This behavior didn’t happen in Next.js 15.
What I’m looking for:
• Is there a way to force middleware to run on the edge runtime in Next.js 16?
• Can be configured to avoid this behavior?
• Any migration tips or config tweaks to reduce invocation load?
If anyone has insights or has dealt with this, I’d really appreciate your help!
I use middleware to handle i18n redirects across my app. In Next.js 15, this middleware ran efficiently on Vercel — it didn’t consume my function invocation quota for every page request. The logs showed edge runtime behavior, and everything was smooth.
After upgrading to Next.js 16, I noticed that every page request now triggers a Node.js runtime invocation for the middleware. The Vercel logs show for each request, and my function quota is draining rapidly.
From what I understand, this is due to the new proxy architecture in Next.js 16, which routes middleware through the Node runtime. While this may enable more advanced features, it’s a huge problem for apps like mine that rely on global middleware for routing.
What I’ve observed:
• Middleware is invoked for every page request.
• Vercel logs show Node runtime () instead of edge.
• Function invocation quota is being consumed aggressively.
• This behavior didn’t happen in Next.js 15.
What I’m looking for:
• Is there a way to force middleware to run on the edge runtime in Next.js 16?
• Can be configured to avoid this behavior?
• Any migration tips or config tweaks to reduce invocation load?
If anyone has insights or has dealt with this, I’d really appreciate your help!
2 Replies
valseOP
Just wanted to follow up with something I discovered that might help others running into the same issue:
🔧 Renaming proxy.ts back to middleware.ts seems to restore the edge runtime behavior on Vercel — and crucially, it stops consuming function invocation quota for every page request.
I found this tip in the [Next.js 16 migration guide](https://nextjs.org/docs/app/guides/upgrading/version-16#middleware-to-proxy), which mentions that middleware.ts still uses the edge runtime, while proxy.ts defaults to Node. However, this distinction isn’t clearly documented in the newer [proxy guide](https://nextjs.org/docs/app/getting-started/proxy#proxy), which could easily lead to confusion.
💡 If you're using middleware for lightweight tasks like i18n redirects (e.g., with next-intl), sticking with middleware.ts is a good fallback to avoid unnecessary Node invocations and quota drain.
Would be great if the docs clarified this more explicitly — especially for folks migrating from Next.js 15 who expect similar behavior.
🔧 Renaming proxy.ts back to middleware.ts seems to restore the edge runtime behavior on Vercel — and crucially, it stops consuming function invocation quota for every page request.
I found this tip in the [Next.js 16 migration guide](https://nextjs.org/docs/app/guides/upgrading/version-16#middleware-to-proxy), which mentions that middleware.ts still uses the edge runtime, while proxy.ts defaults to Node. However, this distinction isn’t clearly documented in the newer [proxy guide](https://nextjs.org/docs/app/getting-started/proxy#proxy), which could easily lead to confusion.
💡 If you're using middleware for lightweight tasks like i18n redirects (e.g., with next-intl), sticking with middleware.ts is a good fallback to avoid unnecessary Node invocations and quota drain.
Would be great if the docs clarified this more explicitly — especially for folks migrating from Next.js 15 who expect similar behavior.
valseOP
There’s no difference between the Node and Edge runtimes when it comes to how Vercel counts function invocations—they're treated the same.
The only effective way I found to reduce the number of invocations was to disable link prefetching. The site gets around a thousand visits per day, and many pages contain a large number of internal links. This was triggering excessive prefetch requests, which in turn caused frequent middleware executions and a spike in function calls
The only effective way I found to reduce the number of invocations was to disable link prefetching. The site gets around a thousand visits per day, and many pages contain a large number of internal links. This was triggering excessive prefetch requests, which in turn caused frequent middleware executions and a spike in function calls