diff --git a/src/content/changelog/workers/2026-10-17-module-registry-default.mdx b/src/content/changelog/workers/2026-10-17-module-registry-default.mdx new file mode 100644 index 00000000000..14b2b3f1dd9 --- /dev/null +++ b/src/content/changelog/workers/2026-10-17-module-registry-default.mdx @@ -0,0 +1,60 @@ +--- +title: Workers will use the new module registry by default on November 1 +description: JavaScript Workers with compatibility dates on or after November 1, 2026 will use URL-based module resolution and import.meta by default. +products: + - workers +date: 2026-10-17 +--- + +import { TypeScriptExample, WranglerConfig } from "~/components"; + +Starting November 1, 2026, JavaScript Workers with a [compatibility date](/workers/configuration/compatibility-dates/) of `2026-11-01` or later will use the new module registry by default. You will no longer need the `new_module_registry` flag for these dates. Python Workers keep using the legacy registry. + +The module registry finds and loads JavaScript modules in your Worker. We [announced the new registry in September 2026](https://blog.cloudflare.com/workers-module-registry-nodejs/). It improves compatibility with JavaScript standards and Node.js. In Workers using [Node.js compatibility](/workers/runtime-apis/nodejs/), you can use `require()` to load ES modules. The module and its dependencies must not use top-level `await`. + +You can also use `import.meta` to get information about the current module and find the URL of another module without loading it: + + + +```ts +export default { + fetch(): Response { + return Response.json({ + moduleUrl: import.meta.url, + isEntrypoint: import.meta.main, + helperUrl: import.meta.resolve("./helper.js"), + }); + }, +} satisfies ExportedHandler; +``` + + + +When deployed with `src/index.ts` as the unbundled entrypoint, `isEntrypoint` is `true`. `helperUrl` is a URL within your Worker bundle. Resolving the URL does not check whether the module exists or load it over the network. Build tools may transform `import.meta`. To try this example directly, refer to [build settings for cf](/cf/wrangler/reference/#build-settings) or [unbundled deployments with Wrangler](/workers/wrangler/configuration/#bundling). + +Existing Workers keep their current behavior until you change their compatibility date or flags. To try the new registry before November 1, keep your current date and add `new_module_registry` to your existing flags. With [`cf`](/cf/get-started/), set `worker.compatibilityFlags` in [`cloudflare.config.ts`](/cf/projects/cloudflare-config/). With Wrangler, set `compatibility_flags`: + + + +```toml +compatibility_flags = ["new_module_registry"] +``` + + + +With `cf`, run `cf dev` to test locally, then `cf deploy` to publish the change. For an existing Wrangler project, follow the [migration guide](/cf/wrangler/migrate/) before switching to `cf`. + +Before updating, check your dependencies for invalid import attributes and changes to `require()` behavior. The new registry rejects invalid import attributes. Calls to `require()` also fail if the module or any of its dependencies use top-level `await`. To keep the legacy registry with a compatibility date of `2026-11-01` or later, add `legacy_module_registry` to the same flags list instead of `new_module_registry`. + +For migration details, refer to the [new module registry compatibility flag](/workers/configuration/compatibility-flags/#new-module-registry), [bundling documentation](/workers/wrangler/bundling/#runtime-module-loading), and [Node.js compatibility documentation](/workers/runtime-apis/nodejs/). diff --git a/src/content/compatibility-flags/new-module-registry.md b/src/content/compatibility-flags/new-module-registry.md new file mode 100644 index 00000000000..0304b79af66 --- /dev/null +++ b/src/content/compatibility-flags/new-module-registry.md @@ -0,0 +1,22 @@ +--- +name: "New module registry" +sort_date: "2026-11-01" +enable_date: "2026-11-01" +enable_flag: "new_module_registry" +disable_flag: "legacy_module_registry" +--- + +For compatibility dates on or after November 1, 2026, JavaScript Workers use the new module registry by default. For earlier dates, add `new_module_registry` to opt in. Add `legacy_module_registry` to retain the legacy registry with a later compatibility date. Python Workers continue to use the legacy registry. + +The registry resolves and loads the modules uploaded with your Worker and the runtime's built-in modules. It provides `import.meta.url`, `import.meta.main`, and `import.meta.resolve()`, and resolves module specifiers as URLs. Different query strings or fragments create separate module instances, even when they refer to the same source. + +Review these differences before changing your compatibility date: + +- Import attributes are validated. Unknown attribute keys, unsupported types, and types that do not match the imported module throw errors. +- `require()` of an ES module returns its namespace unless it exports a value named `"module.exports"`. Workers' built-in `node:` modules return their default export. The `__cjsUnwrapDefault` marker in existing bundles still unwraps the default export. +- `require()` rejects module graphs containing top-level `await`, even if the graph has already finished evaluating. Use dynamic `import()` for these modules. +- The legacy-registry flags `export_commonjs_default`, `require_returns_default_export`, `throw_on_unrecognized_import_assertion`, and `disable_top_level_await_in_require` do not control the new registry. + +The registry does not download modules from arbitrary URLs or install npm dependencies. Your build tooling still determines which modules are uploaded and may transform imports or `import.meta` before deployment. Refer to [Bundling](/workers/wrangler/bundling/#runtime-module-loading) and [Node.js compatibility](/workers/runtime-apis/nodejs/). + +For background and examples, refer to [How we rebuilt Cloudflare Workers' module registry for Node.js compatibility](https://blog.cloudflare.com/workers-module-registry-nodejs/). diff --git a/src/content/docs/workers/wrangler/bundling.mdx b/src/content/docs/workers/wrangler/bundling.mdx index 47e554d7f4a..e0925284e73 100644 --- a/src/content/docs/workers/wrangler/bundling.mdx +++ b/src/content/docs/workers/wrangler/bundling.mdx @@ -25,6 +25,12 @@ You can provide `rules` and set `find_additional_modules` in your configuration Furthermore, we have an escape hatch in the form of [Custom Builds](/workers/wrangler/custom-builds/), which lets you run your own build before Wrangler's built-in one. ::: +## Runtime module loading + +The runtime's module registry resolves and loads the modules that your build uploads. For compatibility dates on or after November 1, 2026, JavaScript Workers use the [new module registry](/workers/configuration/compatibility-flags/#new-module-registry) by default. With earlier dates, add `new_module_registry` to opt in. Use `legacy_module_registry` to opt out with a later date. + +The new registry supports `import.meta.url`, `import.meta.main`, and `import.meta.resolve()`, URL-based module resolution, and validated import attributes. Your bundler may transform these expressions before the runtime receives your code. To preserve your module graph, use [unbundled deployments](/workers/wrangler/configuration/#bundling) or configure [additional modules](#find-additional-modules). + ## Including non-JavaScript modules {/* Changes to this section should also be applied to /workers/vite-plugin/reference/non-javascript-modules */}