Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions src/content/changelog/workers/2026-08-17-new-module-registry.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
---
title: New module registry in Workers improves JavaScript and Node.js compatibility
description: Opt in to standards-based module resolution, import.meta, Node.js require(esm) behavior, lazy compilation, and shared compilation caches.
products:
- workers
date: 2026-08-17
---

import { TypeScriptExample, WranglerConfig } from "~/components";

We've rebuilt the module registry that handles how [ES Modules (ESM)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) and [CommonJS modules](https://nodejs.org/api/modules.html#modules-commonjs-modules) are handled in the Workers runtime, increasing compatbility with standards and the ecosystem of NPM packages.

When you enable the [`new_module_registry` compatbility flag](/workers/configuration/compatibility-flags/#new-module-registry) in your Worker:

* The `import.meta.url`, `import.meta.main`, and `import.meta.resolve()` APIs are fully supported
* Dynamic imports (`await import("/modules/my-module.js");`) are compiled lazily, rather than upfront during your Worker's startup phase
* Your Worker's cold start time may be faster in production, because compiled code can be shared across V8 isolate replicas
* Module specifiers are parsed and resolved as real URLs, including query strings and fragments
* `node:` built-ins resolve to the same module instance no matter how you reach them
* Import attributes (`with { type: 'json' }`) are correctly validated
* `require()` on an ES module follows Node.js' [`require(esm)`](https://nodejs.org/api/modules.html#loading-ecmascript-modules-using-require) rules
* Errors use consistent classes and messages regardless of which loading path triggered them
* WebAssembly modules support [source phase imports](https://github.com/tc39/proposal-source-phase-imports)

## `import.meta` APIs are now fully supported

You can then inspect the current module and resolve another module without importing it:

<TypeScriptExample filename="src/index.ts">

```ts
export default {
async fetch() {
return Response.json({
url: import.meta.url,
main: import.meta.main,
workerPath: import.meta.resolve("./worker.js"),
});
},
};
```

</TypeScriptExample>

## Dynamic imports are compiled lazily

Modules compile when they are first imported. This can reduce cold-start work when you upload separate modules and load them conditionally with a [dynamic `import()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import).

For example, this Worker will only import `report.mjs` when the [isolate](/workers/reference/how-workers-works/) serves a request to `/report` for the first time:

<TypeScriptExample filename="src/index.ts">

```ts
export default {
async fetch(request) {
const url = new URL(request.url);

if (url.pathname === "/report") {
const { generateReport } = await import("../modules/report.mjs");
return new Response(generateReport());
}

return new Response("Hello, world!");
},
};
```

</TypeScriptExample>

Wrangler bundles most JavaScript into the entrypoint by default. To preserve separate modules for runtime loading and take advantage of this new behavior, either use the [Cloudflare Vite Plugin](/workers/vite-plugin/), or configure [Wrangler CLI](/workers/wrangler/) to [upload the dynamically imported module separately](/workers/wrangler/bundling/#find-additional-modules):

<WranglerConfig>

```jsonc
{
"compatibility_date": "$today",
"compatibility_flags": ["new_module_registry"],
"find_additional_modules": true,
"rules": [
{
"type": "ESModule",
"globs": ["modules/**/*.mjs"]
}
]
}
```

</WranglerConfig>

## Source phase imports are now supported for WebAssembly modules

[Source phase imports](/workers/runtime-apis/webassembly/javascript/#source-phase-imports) return a compiled `WebAssembly.Module`. You can instantiate the module with the imports your application requires:

```js
import source wasmModule from "./add.wasm";

const instance = await WebAssembly.instantiate(wasmModule, {});
```

You can also load WebAssembly source dynamically:

```js
const wasmModule = await import.source("./add.wasm");
```

## How to enable the `new_module_registry` compatbility flag

Add the following to your Worker's [configuration file](/workers/configuration/):

<WranglerConfig>

```jsonc
{
"compatibility_date": "$today",
"compatibility_flags": ["new_module_registry"]
}
```

</WranglerConfig>
26 changes: 26 additions & 0 deletions src/content/compatibility-flags/new-module-registry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
_build:
publishResources: false
render: never
list: never

name: "New module registry"
sort_date: "2026-08-05"
enable_flag: "new_module_registry"
disable_flag: "legacy_module_registry"
---

The `new_module_registry` flag replaces the JavaScript Workers module registry with an implementation that resolves specifiers as URLs instead of filesystem-style paths. Python Workers continue to use the legacy module registry.

When enabled, the new registry provides:

- `import.meta.url`, `import.meta.main`, `import.meta.filename`, `import.meta.dirname`, and `import.meta.resolve()` support.
- Specifiers are parsed and resolved as URLs, including query strings and fragments.
- With [`nodejs_compat`](/workers/runtime-apis/nodejs/), `node:` built-ins resolve to the same module instance regardless of how they are reached.
- Import attributes (`with { type: 'json' }`) are correctly validated.
- With `nodejs_compat`, `require()` on an ES module follows Node.js [`require(esm)`](https://nodejs.org/api/modules.html#loading-ecmascript-modules-using-require) rules.
- Consistent error classes and messages across all loading paths.
- Lazy module compilation and shared compiled code across V8 isolate replicas.
- WebAssembly source phase imports.

You must add this flag explicitly to your `compatibility_flags`. For examples and migration details, refer to the [module registry reference](/workers/reference/module-registry/).
Loading