---
title: "16 — Runtimes — Node.js vs Edge"
uid: runtimes
tags: ["roadmap:nextjs", "edge-runtime", "nodejs", "runtimes", "nextjs"]
excerpt: "Node.js is the full-featured default runtime; Edge is the lightweight V8 subset for proximity — the trade is capability versus how close to the user the code runs."
date: 2026-08-13T03:28:00+0000
source: https://www.aveshina.my.id/en/blog/runtimes
---

The word "runtime" used to be background noise until I had to pick between two of them. The model that clicked: **"runtime" means the set of libraries, APIs, and functionality available during execution — and Next.js offers two: Node.js (the default, full-featured) and Edge (a lightweight subset built on V8 — the JavaScript engine that powers Chrome — optimized for proximity to users)** [1][2]. The choice is a capability-vs-proximity trade, and for most code the answer is Node; Edge earns its keep in specific places.

## Node.js — the full-featured default

The **Node.js runtime** has access to all Node.js APIs and is the default for rendering the application [1][3]. It supports every Next.js feature, every npm package (including those that depend on native modules), the filesystem, and the full standard library. Route handlers, Server Components, Server Functions — all run on Node by default.

Node.js itself is a JavaScript runtime that executes JS outside the browser, using an event-driven, non-blocking I/O model suited to scalable network applications [3]. Its dominance on the server is why so much of the npm ecosystem assumes it.

## Edge — lightweight and close to users

The **Edge runtime** is a lightweight JavaScript runtime based on V8, designed to run code closer to the user [1][4]. Code deployed to the edge runs on a globally distributed network of servers, so a request is handled by the nearest instance rather than one origin. The payoff is reduced latency and faster cold starts — the trade is a more limited API surface.

The Edge runtime is a subset of the web platform APIs — it doesn't have the Node.js standard library, can't use most npm packages that depend on Node built-ins, and is intentionally constrained. It's the runtime used by Middleware, which is why middleware is lean and fast [1].

```figure
<svg viewBox="0 0 720 280" xmlns="http://www.w3.org/2000/svg" class="my-6 w-full max-w-2xl" role="img" aria-label="Node.js runtime vs Edge runtime. Left: Node.js — full Node APIs, every npm package, filesystem, all Next.js features, one origin region. Right: Edge — V8 subset, web-standard APIs only, fast cold starts, runs globally near users, used for middleware.">
  <g font-family="ui-sans-serif, system-ui, sans-serif" text-rendering="geometricPrecision">

    <!-- Node -->
    <rect x="40" y="40" width="300" height="200" rx="10" fill="#dcfce7" stroke="#16a34a" stroke-width="1.5"/>
    <text x="190" y="62" font-size="13" font-weight="700" fill="#052e16" text-anchor="middle">Node.js runtime</text>
    <text x="190" y="80" font-size="10" fill="#475569" text-anchor="middle">the default</text>
    <g font-size="10" fill="#052e16">
      <text x="60" y="108">• full Node.js APIs</text>
      <text x="60" y="126">• any npm package (incl. native)</text>
      <text x="60" y="144">• filesystem access</text>
      <text x="60" y="162">• every Next.js feature</text>
      <text x="60" y="180">• one origin region</text>
    </g>
    <text x="190" y="214" font-size="10" font-style="italic" fill="#052e16" text-anchor="middle">capability-first</text>

    <!-- Edge -->
    <rect x="380" y="40" width="300" height="200" rx="10" fill="#e0e7ff" stroke="#6366f1" stroke-width="1.5"/>
    <text x="530" y="62" font-size="13" font-weight="700" fill="#1e1b4b" text-anchor="middle">Edge runtime</text>
    <text x="530" y="80" font-size="10" fill="#475569" text-anchor="middle">V8-based subset</text>
    <g font-size="10" fill="#1e1b4b">
      <text x="400" y="108">• web-standard APIs only</text>
      <text x="400" y="126">• limited npm compatibility</text>
      <text x="400" y="144">• no filesystem / Node built-ins</text>
      <text x="400" y="162">• fast cold starts</text>
      <text x="400" y="180">• runs globally, near users</text>
    </g>
    <text x="530" y="214" font-size="10" font-style="italic" fill="#1e1b4b" text-anchor="middle">proximity-first</text>
  </g>
</svg>
```

## When to pick which

The default is Node, and that's the right answer for the majority of code. Edge earns its keep in specific situations:

- **Middleware** — always runs on Edge by design.
- **Geo/personalization** — when a response depends on the user's location, running at the edge avoids a round trip to the origin.
- **Latency-critical handlers** — a small, fast route that must respond in tens of milliseconds benefits from edge proximity.

The constraint that decides it: if the code needs a Node-only API (filesystem, a native module, a package that assumes Node), it can't run on Edge. The runtime is opt-in per route via a segment config:

```
// app/api/geo/route.ts
export const runtime = 'edge'; // opt this handler into edge

export function GET(request: Request) {
  const country = request.headers.get('x-vercel-ip-country');
  return Response.json({ country });
}
```

## How I use this

I leave everything on Node by default — Server Components, route handlers, Server Functions. The places I reach for Edge are middleware (mandatory) and any handler that's both latency-sensitive and free of Node-only dependencies — geo detection, lightweight auth gates, A/B test assignment. The discipline is to resist the "edge everything" temptation: the constraint on APIs bites when a route grows, and migrating off Edge later means rewriting against a smaller surface.

## References

[1] Vercel, "Edge runtime," Next.js Docs, 2024. [Online]. Available: [https://nextjs.org/docs/app/api-reference/edge](https://nextjs.org/docs/app/api-reference/edge)

[2] "What is Edge Runtime?," edge-runtime.vercel.app, 2024. [Online]. Available: [https://edge-runtime.vercel.app/](https://edge-runtime.vercel.app/)

[3] OpenJS Foundation, "About Node.js," nodejs.org, 2024. [Online]. Available: [https://nodejs.org/en/about/](https://nodejs.org/en/about/)

[4] "Visit the dedicated Node.js roadmap," roadmap.sh, 2024. [Online]. Available: [https://roadmap.sh/nodejs](https://roadmap.sh/nodejs)

```quiz
Q: Which runtime is the default for rendering a Next.js application?
- Edge
- Node.js
correct: 1
explain: Node.js is the default and supports every Next.js feature and every npm package. Edge is opt-in per route.

Q: What's the defining trade-off between Node.js and Edge runtimes?
- Node is faster; Edge is more compatible
- Node is capability-first (full APIs, all packages); Edge is proximity-first (lighter subset, runs near users)
correct: 1
explain: Node gives the full API surface and package compatibility at one origin. Edge trades capability for global proximity and fast cold starts.

Q: Middleware in Next.js runs on…
- Node.js runtime
- Edge runtime
correct: 1
explain: Middleware always runs on the Edge runtime, which is why it stays lean and fast and has a constrained API surface.

Q: What decides whether a route can run on Edge?
- Whether the user is logged in
- Whether the code needs Node-only APIs (filesystem, native modules, packages that assume Node)
correct: 1
explain: If the code depends on Node built-ins or packages that need them, it can't run on Edge. That constraint is the practical decision criterion.

Q: A good Edge runtime use case is…
- a route that reads the filesystem
- a latency-critical geo-detection handler with no Node-only dependencies
correct: 1
explain: Geo/personalization handlers benefit from edge proximity (no origin round trip) and are usually free of Node-only dependencies, making them ideal Edge candidates.
```
