DEV Community

hiro@
hiro@

Posted on Originally published at qiita.com

Comparing Next.js Edge and Node.js: a successful build is not a successful request

Runtime compatibility needs an HTTP execution check as well as an import or build check. In Next.js 16.3.4, the Edge route containing eval built successfully but returned 500 when called.

This version also warns that runtime = 'edge' is deprecated. The official migration notice recommends removing that export and using the default Node.js runtime. This experiment checks compatibility in existing code; it is not a recommendation to adopt Edge for a new application.

Run a Web API-only operation in both runtimes

The first operation reads a query string and returns its UTF-8 byte count and SHA-256:

export async function webResponse(request) {
  const text = new URL(request.url).searchParams.get('text') ?? '';
  const data = new TextEncoder().encode(text);
  const digest = await crypto.subtle.digest('SHA-256', data);
  const hex = Array.from(new Uint8Array(digest), n => n.toString(16).padStart(2, '0')).join('');
  return Response.json({ text, bytes: data.length, sha256: hex });
}
Enter fullscreen mode Exit fullscreen mode

Separate Route Handlers called it with runtime = 'nodejs' and runtime = 'edge'. Sending ?text=fixture returned 200 in both cases, with text fixture, bytes 7, and the same SHA-256. Python independently computed the hash for comparison.

This operation uses Request, URL, TextEncoder, Web Crypto, and Response, and ran in both runtimes. The Edge Runtime API list includes these Web APIs.

That does not establish compatibility for arbitrary npm packages. Check the APIs used by the route and its imported dependencies.

Import a function that reads a file

The next function reads a synthetic fixture.txt inside the test project:

import { readFile } from 'node:fs/promises';
import { join } from 'node:path';
export async function readFixture() {
  return (await readFile(join(process.cwd(), 'fixture.txt'), 'utf8')).trim();
}
Enter fullscreen mode Exit fullscreen mode

Calling it from a Node.js route returned local fixture only with status 200. Importing the same function from an Edge route failed during the build, with UnhandledSchemeError entries for node:fs/promises and node:path.

The import trace continued from the Node module through lib/node-file.js into the Route Handler. It identifies the dependency path as well as the module named in the error.

Changing import syntax to ES Modules would not remove the dependency on Node's file API. This experiment did not add a polyfill or replace local files with external storage.

A successful build can still fail during execution

The Edge comparison also used this code. Its expression is fixed; it does not pass external input into eval.

export const runtime = 'edge';
export function GET() { return Response.json({ value: eval('1 + 2') }); }
Enter fullscreen mode Exit fullscreen mode

The production build exited with 0. Starting that build with next start and issuing GET returned 500 and Internal Server Error. The server logged EvalError: Code generation from strings disallowed for this context.

The Node.js route using the same expression returned 200 with value: 3. Across the 6 conditions, failures appeared at different stages:

Operation Runtime Build HTTP execution
Hash a string with Web APIs Node.js Success 200
Hash a string with Web APIs Edge Success, deprecation warning 200
Node file APIs Node.js Success 200
Import the same file-reading function Edge Failure Not executed
eval of a fixed expression Node.js Success 200, value 3
eval of a fixed expression Edge Success, deprecation warning 500, EvalError

The unsupported Edge APIs reference documents native Node API and dynamic-code-generation restrictions. The table demonstrates that a build does not detect every violation at the same stage.

Do not infer placement or speed from a runtime's name

The tests ran on September 11, 2026, with Next.js 16.3.4, installed React and React DOM 19.3.0, and Node.js 24.15.0 on macOS arm64. They used a webpack production build, cacheComponents: false, no React Compiler, and local next start.

Cloud-region placement, cold starts, database connections, ISR, streaming, and other providers' Workers environments were not measured. These results do not establish that Edge is faster or that Node can reach any connection destination.

The operation, HTTP results, and build/runtime failure records are available. When removing an existing Edge configuration, inspect its APIs and dependencies, then exercise actual requests before deciding compatibility is established.

Top comments (0)