JavaScript/TypeScript Runtimes (Deno, Bun, Edge) & WinterTC Interop

JavaScript/TypeScript Runtimes: Deno 2.x, Bun 1.x, Edge Runtimes & WinterTC Interop

A programming-languages hub reference covering the non-Node JS/TS runtime landscape and the cross-runtime interop standard that ties them together. For Node.js language/runtime APIs and event-loop internals, defer to the sibling references javascript-nodejs.md and nodejs-concurrency-internals.md — this file assumes that foundation and focuses on what differs.

Overview

There are now four practically-relevant server-side JS/TS execution targets:

Runtime Engine Language Killer feature Node compat posture
Node.js V8 JS/TS (via loader) Ecosystem incumbent n/a (the baseline)
Deno 2.x V8 TS-native, JS Secure-by-default, TS w/o config, JSR Backwards-compatible w/ Node + npm
Bun 1.x JavaScriptCore TS-native, JS All-in-one (runtime+pm+test+bundler), speed Drop-in Node replacement, ~90%+ test suite
Edge (workerd / Vercel Edge / Deno Deploy) V8 isolates JS/TS Sub-ms cold start, global POPs Web-standard subset + opt-in Node compat

The unifying thread is WinterTC (formerly WinterCG): the standard defining the Minimum Common Web Platform API — the subset of browser/Web APIs every server runtime implements identically, so code written to that surface is portable across all of them. Understand WinterTC first; it is the shared branch every runtime below inherits from.


Core Concept 1 — WinterTC / WinterCG & the Minimum Common Web Platform API (the shared foundation)

History. WinterCG (Web-interoperable Runtimes Community Group, a W3C CG founded by Cloudflare, Vercel, Deno, Shopify and others) incubated a “minimum common API.” In January 2025 WinterCG was wound down and the work moved to Ecma TC55 (“WinterTC” — Technical Committee on Web-interoperable Server Runtimes). The spec is now ECMA-429 (“Minimum common web API”), adopted by the Ecma General Assembly in December 2025, with yearly snapshots.

What’s in the Minimum Common Web Platform API (the portable surface):

Explicitly NOT required: Web Workers, the DOM (window, document), and HTML element interfaces. (WinterTC plans future conformance levels — e.g. CLI/File-Systems, Graphics, Servers with advanced networking — layered above the minimum.)

Runtime Keys (separate WinterTC registry): standardized identifiers for runtimes used in package.json exports conditions, engines, and runtime detection. Common keys: node, deno, bun, workerd, edge-light, electron, fastly, netlify, react-native, react-server. Keys are immutable once approved and require “proof of use.” Use them to ship runtime-specific entry points:

{ "exports": { "workerd": "./dist/edge.js", "deno": "./dist/deno.js",
               "node": "./dist/node.js", "default": "./dist/default.js" } }

Practical rule: write to the Minimum Common API by default; only branch on a Runtime Key when you genuinely need a runtime-specific capability. Branching is the exception, portability the rule.


Core Concept 2 — Deno 2.x

Deno 2.0 shipped October 2024 (four years after 1.0); the line is now considered stable and production-ready, with a Long-Term Support (LTS) channel.

Headline of 2.x = Node/npm backwards compatibility (the thing that blocked adoption in 1.x):

Defining Deno traits (still true in 2.x):


Core Concept 3 — Bun 1.x (runtime + package manager + test + bundler)

Bun is an all-in-one toolkit written in Zig, powered by JavaScriptCore (not V8) — the JSC choice drives its fast startup and low memory. Positioned as a drop-in Node.js replacement.

Node compatibility: since 1.2, Bun runs the Node.js test suite on every commit; many core modules (node:http, node:http2, node:dgram, node:cluster, node:zlib, etc.) pass >90% of their tests. Bun also implemented V8 C++ APIs inside JSC so native N-API addons (e.g. cpu-features) work unmodified.

As a package manager (bun install) — works in any package.json project:

Built-in runtime APIs (the Bun.* namespace + bun: modules):

Test runner (bun test): Jest-compatible expect, JUnit XML + LCOV for CI, inline snapshots (toMatchInlineSnapshot()), test.only() w/o flags.

Bundler/build: HTML imports, built-in CSS parser (LightningCSS-derived), bytecode caching (~2x faster startup), cross-compilation (build Windows/macOS binaries on Linux), bun build --compile.


Core Concept 4 — Edge Runtimes (workerd / Vercel Edge / Deno Deploy)

Edge runtimes run JS in V8 isolates (lightweight contexts, not containers) distributed across global POPs — sub-millisecond cold starts, no per-request VM boot. The execution model is a handler: Request → Response. They expose the WinterTC Minimum Common API, not full Node.

Hard constraints to design around:

Providers:

Compatibility-date discipline (Cloudflare): the compatibility_date (+ optional compatibility_flags) pins runtime behavior. Bumping the date can flip on new Node modules or change defaults — treat it as a deliberate, tested upgrade, not a passive value.


Core Concept 5 — Choosing & migrating between runtimes

Decision guide:

Portability strategy (works everywhere):

  1. Code to the Minimum Common Web Platform API (fetch/streams/Web Crypto/URL/TextEncoder).
  2. Prefer ESM; use package.json exports with Runtime Keys only for genuine per-runtime branches.
  3. Keep Node-specific built-ins (fs, net, native addons) behind an abstraction so edge targets can swap them for a Web-standard or platform primitive.
  4. Verify with each runtime’s compat tracking (Bun’s Node test-suite pass rate; Cloudflare’s nodejs_compat + compat-date matrix; Deno’s node:/npm: support).

Practical Patterns

Anti-Patterns

Troubleshooting

References