With Next.js 16.3, the runtime = 'edge' setting at the route and page level is no longer supported — Vercel's official documentation states this plainly: every route and page using this configuration now runs on the Node.js runtime. If your project still has export const runtime = 'edge' lines, this article shows you where to look, what might break when moving to Node, and why proxy.ts was never affected.
💡 Pro Tip: Deleting theruntime = 'edge'line from route/page files usually breaks nothing — because Node.js is already the default runtime; if you had to give upfs, a native module, or the full Node.js API surface because ofruntime = 'edge', deleting the line brings that code back within reach.
Table of Contents
- What changed, in one sentence
- Two docs seem to say two things — the real distinction (route/page vs proxy.ts)
- Finding where runtime='edge' is used
- What breaks moving to Node: fs, native modules, duration limits
- APIs you can now use
- proxy.ts stays on Node, edge only in the old middleware.ts: the limits
- Fluid compute + Active CPU's billing impact
- What this means if you run your own server
- FAQ
- Why doesn't runtime = 'edge' work in Next.js 16.3?
- Was edge runtime removed entirely, or does it still exist in proxy.ts?
- How do you migrate from edge runtime to the Node.js runtime?
- What happens to cold start and cost once edge is removed?
- What happens if I write runtime = 'edge' in proxy.ts?
- Conclusion
- Sources
What changed, in one sentence
Vercel's official runtime documentation says: "Starting in Next.js 16.3, setting runtime = 'edge' is no longer supported. Routes and pages run on Node.js." In other words, export const runtime = 'edge' in route handlers (route.ts), pages (page.tsx), and layouts no longer has any effect and is expected to be removed. Next.js's own route-segment-config reference points the same way: the 'edge' value of the runtime option is now marked "deprecated," while 'nodejs' is the default and recommended value.
The practical implication is simple: a project that deliberately opted into the edge runtime before 16.3 now runs that code on Node.js, with identical surface behavior. Next.js's own deprecation message page summarizes the migration this way: "The Node.js runtime is the default, so no replacement is needed" — meaning the action is usually just deleting the line.
Worth noting: this change isn't called out in Next.js's 16.3 release announcement (blog.next-16-3) — the removal is documented only in Vercel's platform docs and Next.js's reference/message pages. So it's more accurate to read this not as "Next.js officially announced it," but as "Next.js's own documentation and Vercel's platform documentation were quietly updated."
Two docs seem to say two things — the real distinction (route/page vs proxy.ts)
Scanning Next.js's own documentation, you may hit a confusing contradiction. The Edge Runtime reference page (/docs/app/api-reference/edge) seems to point to Proxy as a place Edge Runtime is used. But the route-segment-config reference and the Proxy file-convention page say the opposite: "This option cannot be used in Proxy" and "Proxy defaults to using the Node.js runtime. The runtime config option is not available in Proxy files. Setting the runtime config option in Proxy will throw an error."
These two statements genuinely contradict each other — a stale, unupdated remnant of the docs, not an ambiguity in your code. The actual behavior is clear: the proxy.ts file has never allowed setting `runtime = 'edge'`, it runs on the Node.js runtime by default, and attempting that setting throws an error. runtime = 'edge' at the route/page level is a separate story: it was "deprecated but working" up to 16.3, and became officially unsupported in 16.3.
The real point of confusion here is the timeline. Proxy defaulting to the Node.js runtime and rejecting the runtime config arrived in version 16.0.0 (alongside middleware being renamed to Proxy) — not in 16.3. What changed in 16.3 isn't Proxy; it's the complete removal of runtime = 'edge' support at the route and page segment level. Not mixing up these two different versions and two different mechanisms is the single most critical point of this article.
Mechanism | Edge support | When it changed | Source |
|---|---|---|---|
Route / Page ( route.ts, page.tsx) | Deprecated-but-working up to 16.3, fully removed in 16.3 | Next.js 16.3 (August 2026) | Vercel edge runtime documentation |
Proxy ( proxy.ts, formerly middleware.ts) | Has never accepted the runtime config since being born as Proxy, defaults to Node.js | Next.js 16.0.0 (October 2025) | Proxy file-convention reference |
Edge Runtime API reference | Still carries an old statement associating it with Proxy | Not updated since February 2026 (lastUpdated 2026-02-02) | Edge Runtime API reference |
Finding where runtime='edge' is used
Before starting the migration, find every file that uses the runtime = 'edge' export. This line is only valid in route handlers, pages, and layouts — proxy.ts already rejects it, so focus your search on route/page/layout files inside app/.
1grep -rn "runtime.*=.*['\"]edge['\"]" app/ --include="*.ts" --include="*.tsx"For each candidate line you find, ask three questions: (1) Is this line actually necessary, or is it a leftover copy-paste? (2) Does the code inside use fs, a native Node.js module, or an API edge doesn't support? (3) Does the route still compile after you remove it? Next.js's own deprecation message recommends the same approach: delete the line, because Node.js is already the default runtime and no other change is usually needed.
Before and after for a route file looks like this:
1// Before (pre-16.3, no longer supported)2export const runtime = "edge";3 4export async function GET(request: Request) {5 return new Response("ok");6}1// After (Node.js default, line removed entirely)2export async function GET(request: Request) {3 return new Response("ok");4}Next.js's route-segment-config reference summarizes the two values this way: 'nodejs' (default) and 'edge' (deprecated). So deleting the runtime export entirely produces the same result as explicitly writing 'nodejs' — but deleting the line is cleaner, because you won't have to ask "was I using edge?" again in the future.
Two false positives can creep in: an unrelated variable named runtimeConfig, and stale runtime references inside proxy.ts (likely dead code, since that config isn't accepted there anyway). Scoping the regex to app/ and .ts/.tsx also eliminates false matches in node_modules and .next/.
What breaks moving to Node: fs, native modules, duration limits
Edge runtime's biggest constraint was its lack of access to most Node.js APIs. Vercel's documentation describes this clearly: Edge Runtime is built on the V8 engine and exposes only a subset of Web APIs like fetch, Request, Response — the fs module, native Node.js addons, or the full Node.js API surface fall outside that subset. Moving to the Node.js runtime removes these constraints: you can access the filesystem, use native modules (e.g., image processing, cryptography libraries).
There's also a difference on duration limits. Vercel's official limit for Edge Functions is: you must start sending a response within 25 seconds, while streaming can last up to 300 seconds. When you move to the Node.js runtime, this becomes subject to Vercel's Node.js function limits and Fluid Compute's own rules — so saying "the duration limit is gone" would be wrong; the limit model changes.
On the ISR (Incremental Static Regeneration) side, Next.js's Edge Runtime reference states the situation plainly: "The Edge Runtime does not support Incremental Static Regeneration (ISR)." So a page using ISR could never run on edge in the first place; the runtime = 'edge' removal creates no behavior change for those pages.
APIs you can now use
A route handler example that doesn't work on edge but runs fine on Node.js looks like this — say, when you want to read and cache a statically generated file at build time:
1import { readFile } from "node:fs/promises";2import { join } from "node:path";3 4export async function GET() {5 // node:fs is not supported in the edge runtime — you can't6 // read from or write to the filesystem; this call works7 // normally in the Node.js runtime.8 const filePath = join(process.cwd(), "data", "config.json");9 const contents = await readFile(filePath, "utf-8");10 11 return Response.json(JSON.parse(contents));12}If you'd marked a route like this with runtime = 'edge' before 16.3, it wouldn't have worked: Next.js's Edge Runtime reference says it plainly — "Native Node.js APIs are not supported. For example, you can't read or write to the filesystem." According to Vercel's documentation, Edge Runtime only provides a subset of Web APIs like fetch, Request, Response, crypto/SubtleCrypto, ReadableStream/WritableStream/TransformStream, TextEncoder/TextDecoder — node:fs isn't on that list. On the Node.js runtime, this call works like a normal Node.js API.
Capability | Edge Runtime | Node.js Runtime |
|---|---|---|
fetch, Request, Response | Yes | Yes |
crypto.subtle (Web Crypto) | Yes | Yes |
node:fs (filesystem) | No | Yes |
Native Node.js addons | No | Yes |
Response start-time limit | 25 seconds | Subject to Vercel's Node.js function limits |
Streaming upper bound | 300 seconds | Subject to Fluid Compute rules |
proxy.ts stays on Node, edge only in the old middleware.ts: the limits
proxy.ts (formerly middleware.ts) is Next.js's file convention for running code on the server before a request completes. The official definition: "The proxy.js|ts file is used to write Proxy and run code on the server before a request is completed... Proxy executes before routes are rendered." You can change the response through rewrites, redirects, header modification, or by producing a response directly.
But Proxy has its own officially stated limits — rules that hold regardless of the runtime = 'edge' removal:
- Not for slow data fetching: "Proxy is not intended for slow data fetching... it should not be used as a full session management or authorization solution." Using Proxy for a heavy DB query or a slow third-party API call isn't recommended.
- fetch cache options have no effect:
fetch'scache,revalidate, andtagsoptions have no effect inside Proxy. - Runs on every request without a matcher: If you don't define a matcher, Proxy runs on every request, including static files under
_next/static,_next/image, and thepublic/folder. If you put auth logic in Proxy and forgot the matcher, you may have accidentally routed even your CSS/JS/images through that code path.
1// proxy.ts — using a matcher to avoid unnecessary runs2export const config = {3 matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],4};The official upgrade guide is clear here: "The edge runtime is NOT supported in proxy. The proxy runtime is nodejs, and it cannot be configured. If you want to continue using the edge runtime, keep using middleware." It immediately follows up by noting further edge guidance is coming in a future minor release: "We will follow up on a minor release with further edge runtime instructions."
This comes at a cost: the Next.js 16 announcement explicitly declares middleware.ts's lifespan limited — "The middleware.ts file is still available for Edge runtime use cases, but it is deprecated and will be removed in a future version." So staying on the middleware file for edge is valid but not a permanent solution — it means waiting inside a deprecated file convention.
Fluid compute + Active CPU's billing impact
Vercel's Fluid Compute model has been the default for new projects since April 23, 2025, combining serverless flexibility with server-like capabilities: sharing a single instance across requests, background processing via waitUntil, automatic cold-start optimization.
The biggest difference on the billing side is the Active CPU concept: code is billed only for the milliseconds it's actually executing. While waiting on a database query or an AI model call (I/O wait time), CPU billing pauses — but Provisioned Memory billing continues during that wait. The official documentation summarizes it this way: "You are only billed during actual code execution and not during I/O operations" (for CPU) and, for memory, "Continues billing while handling requests, even during I/O operations."
There are also regional price differences — for example, in the Frankfurt (fra1) region Active CPU is $0.184/hour and Provisioned Memory is $0.0152/GB-hour, while in the Washington D.C. (iad1) region Active CPU is $0.128/hour. Moving to the Node.js runtime doesn't change this billing model; both edge and Node.js functions now run under the same Fluid Compute + Active CPU framework. Vercel recommends moving to Node.js citing "improved performance and reliability"; it doesn't publish a concrete cold-start or cost comparison.
What this means if you run your own server
If your project runs on your own VPS as a Node.js standalone server and systemd service (like this site's portfolio-ssr.service setup), this change creates no practical break. runtime = 'edge' was already a Vercel Edge Function optimization — its V8-isolated, container-free model is meaningless on your own server, since the whole process already runs in one Node.js runtime.
The one concrete effect: if your project still has a runtime = 'edge' export, you need to remove it — otherwise you'll get a deprecation warning at build time. The Fluid Compute and Active CPU billing model is entirely specific to Vercel's platform; it has no equivalent on your own server, because you've already allocated a fixed resource for a fixed process (systemd service + fixed RAM/CPU).
Bringing the migration steps together into a single checklist:
- Search: List all candidates with
grep -rn "runtime.*edge" app/. - Remove: Delete the
export const runtime = 'edge'line from every route/page file (Node.js is already the default). - Build: Run
next build, confirm no deprecation warning remains. - Keep Proxy separate: Don't add a
runtimeconfig to proxy.ts files — it's not accepted there and throws an error. - Check the matcher: Make sure Proxy isn't running unnecessarily on static files.
- Test fs/native modules: Add the Node.js APIs that didn't work on edge but you now want to use (filesystem, native crypto) to your routes and test them.
GOLDEN TIP
The most valuable insight in this article
This tip holds the article's most important takeaway.
Easter Egg
You found a hidden gem!
There's a hidden detail in this section. Want to uncover it?
Reader Reward
We've gathered the steps you shouldn't skip when applying this article's migration process to your own project into a single checklist. Checking off every item lets you be confident that the runtime = 'edge' removal is safely complete on both the route/page and proxy.ts sides.
FAQ
Why doesn't runtime = 'edge' work in Next.js 16.3?
Vercel's official documentation says it directly: "Starting in Next.js 16.3, setting runtime = 'edge' is no longer supported. Routes and pages run on Node.js." Next.js's own route-segment-config reference also marks the edge value as deprecated and shows nodejs as the only recommended value. So this isn't a bug — it's the framework's deliberate decision to make Node.js the single standard runtime.
Was edge runtime removed entirely, or does it still exist in proxy.ts?
Neither is entirely accurate. proxy.ts (formerly middleware.ts) has not accepted the runtime config since Next.js 16.0.0, and runs on Node.js by default — that's a rule 16.0 brought, not 16.3. What changed in 16.3 is the removal of runtime = 'edge' support at the route and page level. The official upgrade guide also says where edge still lives: "If you want to continue using the edge runtime, keep using middleware." So edge only survives in the deprecated middleware.ts file convention. Next.js's Edge Runtime API reference page still carries an old statement associating Edge with Proxy, but that looks like an unupdated line that contradicts the official upgrade guide and the proxy file-convention page.
How do you migrate from edge runtime to the Node.js runtime?
Just delete the export const runtime = 'edge' line from route/page files entirely — no other change is usually needed since Node.js is already the default runtime. Before deleting, it's recommended to list all candidates with grep -rn "runtime.*edge" app/, then check each one for whether it needs an API edge doesn't support (fs, native modules).
What happens to cold start and cost once edge is removed?
There isn't a definitive number to answer this with right now — Next.js's 16.3 release announcement doesn't mention this at all, and Vercel's general documentation only says it recommends moving to Node.js for "improved performance and reliability," without publishing a concrete cold-start or cost comparison. The one known fact is that both edge and Node.js functions now run under the same Fluid Compute + Active CPU billing model — Active CPU only charges for the time code is actually running; CPU billing pauses during I/O wait, but memory billing continues.
What happens if I write runtime = 'edge' in proxy.ts?
You get an error. The Proxy file-convention reference is clear: "The runtime config option is not available in Proxy files. Setting the runtime config option in Proxy will throw an error." This is different from the deprecation warning on routes/pages — trying this setting in Proxy directly results in a build/runtime error.
Conclusion
Next.js 16.3's runtime = 'edge' removal is, for most codebases, a one-line cleanup: deleting this export from routes and pages usually breaks nothing else, since Node.js is already the default. The point that actually deserves your attention is that this is an entirely separate change from proxy.ts's behavior (already tied to Node.js since 16.0) — two different versions, two different mechanisms.
If you're more interested in the edge/serverless ecosystem on the backend side, the Supabase Edge Functions and Deno runtime piece shows how an edge-native alternative works; the Drizzle ORM + Turso edge SQLite pattern covers database access suited to edge runtime constraints. If you want to compare serverless frameworks, the Hono.js production guide is a useful reference. If you want to add this kind of deprecation check to your CI/CD pipeline, the pipeline logic in iOS CI/CD Pipeline: GitHub Actions and Fastlane can be adapted platform-independently. For what to watch for when building a production-ready API layer, the Network Layer Optimization guide shares the same discipline as this article: proceed from sources, not assumptions.
Sources
- Vercel Edge Runtime Documentation — documents that
runtime = 'edge'support was removed in 16.3, and Edge Runtime's V8-based Web API subset. - Next.js Route Segment Config Reference — runtime — documents the
nodejs(default) andedge(deprecated) values and that it can't be used in Proxy. - Next.js Edge Runtime Deprecated Message Page — gives the migration instruction ("no replacement is needed") under "Why This Warning Occurred."
- Next.js 16 Upgrade Guide — documents that
edgeruntime isn't supported inproxy, and that you should stay onmiddlewareif you need edge. - Next.js 16 Release Announcement — documents that
proxy.tsruns on the Node.js runtime and thatmiddleware.tsis deprecated. - Next.js Proxy File Convention Reference — documents Proxy's Node.js default, matcher behavior, and the runtime config restriction.
- Next.js Proxy Conceptual Guide — explains the middleware-to-proxy transition and Proxy's usage limits (slow data fetching, fetch cache ineffectiveness).
- Next.js 16.3 Release Announcement — documents 16.3's general improvements (TypeScript 7, memory usage, native streams).
- Vercel Fluid Compute Documentation — documents Fluid Compute's default-enabled date and execution model.
- Vercel Functions Usage and Pricing — documents the Active CPU and Provisioned Memory billing mechanics and regional pricing.
Tags
iOS Development News
Weekly Swift tips, SwiftUI tricks and iOS best practices. No spam, only valuable content.
We respect your privacy. You can unsubscribe at any time.

