# What Is the Node.js Compatibility Layer in Workerd?

> Explore the Node.js compatibility layer in Workerd. Enable standard nodejs_compat imports for fs, http, and crypto APIs within your Workers.

- Repository: [Cloudflare/workerd](https://github.com/cloudflare/workerd)
- Tags: deep-dive
- Published: 2026-03-18

---

**The Node.js compatibility layer in workerd is a flag-gated collection of internal C++ modules that exposes Node.js built-in APIs—such as `fs`, `http`, and `crypto`—to Workers, enabling standard `node:` prefixed imports when the `nodejs_compat` compatibility flag is activated.**

The **Node.js compatibility layer** allows Cloudflare's `workerd` runtime to execute code written for Node.js by providing sandboxed implementations of native Node modules. This system bridges the gap between Node.js APIs and workerd's secure, isolate-based architecture, letting developers import modules like `node:fs` and `node:http` directly inside their Workers.

## Architecture of the Compatibility Layer

The layer consists of two coordinated components: **C++ native implementations** that provide the actual functionality, and **TypeScript shims** that expose these implementations through standard `node:` import specifiers. The system is controlled through compatibility flags defined in the runtime's configuration schema.

### Compatibility Flags and Feature Toggles

The availability of the Node.js compatibility layer is determined by the `nodeJsCompat` and `nodeJsCompatV2` flags declared in `src/workerd/io/compatibility-date.capnp`. When a Worker starts, the runtime evaluates these flags to decide which modules to expose.

In [`src/workerd/api/node/node.h`](https://github.com/cloudflare/workerd/blob/main/src/workerd/api/node/node.h), the helper function `isNodeJsCompatEnabled` checks these flags at runtime:

```cpp
bool isNodeJsCompatEnabled(auto featureFlags) {
  return featureFlags.getNodeJsCompat() || featureFlags.getNodeJsCompatV2();
}

```

If this check returns false, only minimal internal modules (such as those required for `console` output) remain available. If true, the system proceeds to evaluate per-module flags like `enableNodeJsFsModule` and `enableNodejsHttpModules` to determine exactly which APIs to surface.

### Module Registration Flow

The central registration logic resides in `registerNodeJsCompatModules`, defined in [`src/workerd/api/node/node.h`](https://github.com/cloudflare/workerd/blob/main/src/workerd/api/node/node.h). This function wires the C++ implementations into the JavaScript runtime through the JSG (JavaScript Glue) module system:

```cpp
template <class Registry>
void registerNodeJsCompatModules(Registry& registry, auto featureFlags) {
  // Register C++ modules as built-ins
  NODEJS_MODULES(V);  // Macro expands to addBuiltinModule<T>(name, INTERNAL)
  
  if (featureFlags.getWorkerdExperimental()) {
    NODEJS_MODULES_EXPERIMENTAL(V);
  }
  
  // Filter the JavaScript bundle based on flags
  bool nodeJsCompatEnabled = isNodeJsCompatEnabled(featureFlags);
  registry.addBuiltinBundleFiltered(NODE_BUNDLE, [&](jsg::Module::Reader module) {
    if (!nodeJsCompatEnabled) return module.getType() == jsg::ModuleType::INTERNAL;
    if (isNodeHttpModule(module.getName())) return featureFlags.getEnableNodejsHttpModules();
    if (module.getName() == "node:fs"_kj) return featureFlags.getEnableNodeJsFsModule();
    return true;
  });
}

```

This function performs two critical tasks. First, it registers all internal C++ modules (found in `src/workerd/api/node/*.c++`) as built-in modules available to the JavaScript engine. Second, it filters the `NODE_BUNDLE`—a compiled JavaScript bundle generated from the TypeScript sources in `src/node/*.ts`—based on the current feature flags.

### The TypeScript Shim Layer

The public API surface is provided by TypeScript files under `src/node/` that re-export the underlying C++ functionality. These shims use standard `node:` import specifiers (e.g., `node:fs`, `node:http`) that mirror Node.js's own module resolution. When bundled into `NODE_BUNDLE`, these files create the mapping between JavaScript `import` statements and the native C++ implementations.

## Enabling Node.js APIs in Your Worker

To use the **Node.js compatibility layer in workerd**, you must enable the appropriate compatibility flag in your Workerd configuration and import modules using the `node:` prefix.

### Configuration Example

Activate the layer in your `.capnp` configuration file by including the `nodejs_compat` flag:

```capnp
const unitTests :Workerd.Config = (
  services = [(
    name = "my-worker",
    worker = (
      modules = [(name = "worker", esModule = embed "my-worker.js")],
      compatibilityFlags = ["nodejs_compat"],
    ),
  )],
);

```

The `compatibilityFlags` array accepts `nodejs_compat` or `nodejs_compat_v2`, both of which trigger the `isNodeJsCompatEnabled` check in the runtime.

### Importing Node.js Modules

Once enabled, your Worker can import Node.js built-ins exactly as you would in a standard Node.js environment:

```javascript
// my-worker.js
import { readFile } from "node:fs";
import http from "node:http";

readFile("example.txt", "utf8", (err, data) => {
  if (err) throw err;
  console.log("File contents:", data);
});

http.createServer((req, res) => {
  res.writeHead(200);
  res.end("Hello from Node-compatible Workerd!");
}).listen(8080);

```

These imports resolve to the C++ implementations in `src/workerd/api/node/fs.c++` and `src/workerd/api/node/http.c++`, providing native-like performance while maintaining workerd's security sandbox.

### Granular Module Control

You can expose specific modules without enabling the entire compatibility layer using per-module feature flags. For example, to enable only the file system module while disabling HTTP:

```capnp
compatibilityFlags = [
  "nodejs_compat",
  "enable_nodejs_fs_module",
  "no_enable_nodejs_http_modules"
];

```

The `registerNodeJsCompatModules` function checks these flags individually when filtering the `NODE_BUNDLE`, allowing precise control over which Node.js APIs are available to your Worker.

## Key Implementation Files

Understanding the **Node.js compatibility layer** requires familiarity with these specific source files in the `cloudflare/workerd` repository:

- **[`src/workerd/api/node/node.h`](https://github.com/cloudflare/workerd/blob/main/src/workerd/api/node/node.h)** — Contains the `registerNodeJsCompatModules` function, the `isNodeJsCompatEnabled` helper, and the `NODEJS_MODULES` macro that lists all available C++ modules.
- **`src/workerd/io/compatibility-date.capnp`** — Defines the Cap'n Proto schema for `nodeJsCompat`, `nodeJsCompatV2`, and per-module flags like `enableNodeJsFsModule`.
- **[`src/workerd/api/modules.h`](https://github.com/cloudflare/workerd/blob/main/src/workerd/api/modules.h)** — Calls `registerNodeJsCompatModules` during the global JSG module registry construction.
- **`src/workerd/api/node/*.c++`** — C++ implementations of individual Node.js modules (e.g., `fs.c++`, `http.c++`, `crypto.c++`).
- **`src/node/*.ts`** — TypeScript façade files that provide the public `node:` entry points and are compiled into the `NODE_BUNDLE`.
- **[`src/node/README.md`](https://github.com/cloudflare/workerd/blob/main/src/node/README.md)** — High-level documentation describing the shim layer architecture.
- **`src/workerd/api/node/tests/*-nodejs-test.wd-test`** — End-to-end test files (such as `fs-nodejs-test.wd-test`) that validate the compatibility layer behavior.

## Summary

- The **Node.js compatibility layer** is a flag-gated system in `workerd` that exposes Node.js built-in modules through internal C++ implementations and TypeScript shims.
- Activation requires the `nodejs_compat` or `nodejs_compat_v2` flag in the Workerd configuration, triggering the `isNodeJsCompatEnabled` check in [`src/workerd/api/node/node.h`](https://github.com/cloudflare/workerd/blob/main/src/workerd/api/node/node.h).
- The `registerNodeJsCompatModules` function registers C++ modules and filters the `NODE_BUNDLE` at runtime based on per-module feature flags.
- Modules are implemented in `src/workerd/api/node/*.c++` and exposed via `node:` imports through the TypeScript shims in `src/node/*.ts`.
- Granular control allows enabling specific modules (like `fs` or `http`) individually without activating the entire compatibility suite.

## Frequently Asked Questions

### What is the difference between `nodejs_compat` and `nodejs_compat_v2`?

Both flags enable the Node.js compatibility layer in workerd by triggering the `isNodeJsCompatEnabled` function in [`src/workerd/api/node/node.h`](https://github.com/cloudflare/workerd/blob/main/src/workerd/api/node/node.h), which returns true if either flag is set. The specific behavioral differences between v1 and v2 are defined in the compatibility-date schema at `src/workerd/io/compatibility-date.capnp`, with v2 typically representing an updated or expanded set of supported APIs and behaviors.

### Can I use all Node.js modules in workerd?

No, workerd implements a subset of Node.js built-in modules based on security constraints and runtime capabilities. The available modules are listed in the `NODEJS_MODULES` macro in [`src/workerd/api/node/node.h`](https://github.com/cloudflare/workerd/blob/main/src/workerd/api/node/node.h) and include common APIs like `fs`, `http`, `crypto`, and `process`, but exclude others that conflict with the sandboxed Worker environment. Per-module flags like `enableNodeJsFsModule` allow granular control over which specific modules are exposed.

### How does workerd handle Node.js module security?

The Node.js compatibility layer maintains workerd's security model by implementing Node.js APIs as **internal C++ modules** that operate within the existing sandbox restrictions. File system operations in `node:fs`, for example, are subject to the same read-only or restricted access constraints as standard workerd storage APIs. The `registerNodeJsCompatModules` function ensures that only explicitly enabled modules are exposed, preventing unauthorized access to potentially dangerous native functionality.

### Where are the actual Node.js API implementations located?

The concrete implementations reside in `src/workerd/api/node/*.c++` files (such as `fs.c++`, `http.c++`, and `crypto.c++`). These C++ files provide the native functionality that backs the JavaScript-facing APIs. The public `node:` import specifiers are defined in `src/node/*.ts` as TypeScript shims that forward calls to these C++ implementations, creating the bridge between standard Node.js code patterns and workerd's native runtime.