export const runtime

Selects the JavaScript runtime used to render a route segment.

Signature
export const runtime = 'nodejs'
// 'nodejs'

Parameters

ParameterTypeDescription
$'nodejs'optionalstring literal= 'nodejs'Default. Renders the route with the Node.js runtime, where the full Node.js API surface is available.
$'edge'optionalstring literalDeprecated. Renders the route with the Edge Runtime. The docs advise removing the runtime export entirely; Node.js is the default, so no replacement is needed.

Errors

The option cannot be used in Proxy (proxy.js / proxy.ts) — the proxy runtime is nodejs and cannot be configured.

Changelog

  • PHP v15.0.0-RCexport const runtime = "experimental-edge" deprecated. The app-dir-runtime-config-experimental-edge codemod rewrites it to 'edge'.
  • PHP v16.xThe Edge Runtime is deprecated; the docs tell you to delete the runtime export rather than change its value. Cache Components requires the Node.js runtime. The API reference marks 'edge' deprecated without naming an exact version.

runtime picks the JavaScript runtime for a page, layout, or route file and everything nested below it. In current Next.js there is effectively one answer: 'nodejs', which is the default, so the healthiest version of this export is no export at all.

What actually matters now

The Edge Runtime is deprecated. If you are reading this because a route already says export const runtime = 'edge', the documented migration is to delete the line — Node.js is the default and needs no replacement. This applies to every file that supports the config: page.ts, layout.ts, route.ts, and Pages Router API routes.

What trips people up

  • Proxy does not accept it. proxy.ts (the file that replaced middleware.ts) always runs on Node.js and its runtime cannot be configured. If you need the Edge Runtime for that layer, you stay on middleware.
  • It is inherited. Putting 'edge' on a layout drags every page beneath it onto the Edge Runtime, which is where the mysterious "Module not found: Can't resolve 'fs'" reports come from.
  • Cache Components requires Node.js. Any route still exporting 'edge' has to be migrated before you enable cacheComponents.

Example

Example · typescript
export const runtime = 'nodejs'

import { createHash } from 'node:crypto'

export async function POST(request: Request) {
  const body = await request.arrayBuffer()
  const digest = createHash('sha256').update(Buffer.from(body)).digest('hex')

  return Response.json({ digest })
}

When to use it

  • Delete a leftover runtime = 'edge' export while migrating a project to Next.js 16.
  • Make the Node.js runtime explicit on a route handler that uses node:crypto or the filesystem.
  • Audit which segments still pin a runtime before enabling cacheComponents.

Frequently asked questions

Should I still use export const runtime = 'edge' in Next.js 16?

No — the Edge Runtime is deprecated and the documented fix is to remove the runtime export entirely, since 'nodejs' is the default and needs no replacement.

Why can't I set the runtime in proxy.ts?

Because the proxy layer always runs on the Node.js runtime and that cannot be configured; if you need the Edge Runtime at that layer you have to stay on the deprecated middleware convention.

How do I convert runtime = 'experimental-edge' to the supported value?

Run npx @next/codemod@latest app-dir-runtime-config-experimental-edge . which rewrites 'experimental-edge' to 'edge' — though 'edge' is itself now deprecated, so removing the export is the better end state.

More examples

Migrating a route off the Edge Runtime

The documented migration for the Edge Runtime deprecation warning is a deletion, not a value change. The handler itself is unchanged — it was already using standard Request and Response objects, which work identically on Node.js.

Example · typescript
// app/api/geo/route.ts

// Before — deprecated:
// export const runtime = 'edge'

// After: remove the export. Node.js is the default,
// so there is nothing to replace it with.

export async function GET(request: Request) {
  const country = request.headers.get('x-vercel-ip-country') ?? 'unknown'

  return Response.json({ country })
}

Inheritance from a layout

Demonstrates that runtime is a segment-level setting inherited by children. It is also why a stray 'edge' on a shared layout breaks unrelated pages that import Node.js built-ins such as node:fs.

Example · typescript
// app/(fast)/layout.tsx
// Setting a runtime here applies to every page below it.
export const runtime = 'nodejs'

export default function FastLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return <div>{children}</div>
}

// app/(fast)/report/page.tsx
// Inherits 'nodejs' from the layout; no export needed here.
import { readFile } from 'node:fs/promises'

export default async function ReportPage() {
  const csv = await readFile('./data/report.csv', 'utf8')
  return <pre>{csv.slice(0, 200)}</pre>
}

Why proxy.ts rejects the export

proxy.ts replaced middleware.ts in Next.js 16 and always runs on Node.js. The runtime segment config is one of the few exports that does not carry over from the old middleware file, so an unedited copy of a middleware file is a common source of this error.

Example · typescript
// proxy.ts
import { NextResponse } from 'next/server'

// Not supported here — the proxy runtime is nodejs
// and cannot be configured:
// export const runtime = 'edge'

export function proxy(request: Request) {
  const url = new URL(request.url)

  if (url.pathname === '/old') {
    return NextResponse.redirect(new URL('/new', request.url))
  }

  return NextResponse.next()
}

export const config = {
  matcher: ['/old', '/dashboard/:path*'],
}

Discussion

  • Be the first to comment on this lesson.