diff --git a/src/content/changelog/workers/2026-08-17-new-module-registry.mdx b/src/content/changelog/workers/2026-08-17-new-module-registry.mdx
new file mode 100644
index 00000000000..001ca4a5014
--- /dev/null
+++ b/src/content/changelog/workers/2026-08-17-new-module-registry.mdx
@@ -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:
+
+
+
+```ts
+export default {
+ async fetch() {
+ return Response.json({
+ url: import.meta.url,
+ main: import.meta.main,
+ workerPath: import.meta.resolve("./worker.js"),
+ });
+ },
+};
+```
+
+
+
+## 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:
+
+
+
+```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!");
+ },
+};
+```
+
+
+
+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):
+
+
+
+```jsonc
+{
+ "compatibility_date": "$today",
+ "compatibility_flags": ["new_module_registry"],
+ "find_additional_modules": true,
+ "rules": [
+ {
+ "type": "ESModule",
+ "globs": ["modules/**/*.mjs"]
+ }
+ ]
+}
+```
+
+
+
+## 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/):
+
+
+
+```jsonc
+{
+ "compatibility_date": "$today",
+ "compatibility_flags": ["new_module_registry"]
+}
+```
+
+
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..e42375da54d
--- /dev/null
+++ b/src/content/compatibility-flags/new-module-registry.md
@@ -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/).
diff --git a/src/content/docs/workers/reference/module-registry.mdx b/src/content/docs/workers/reference/module-registry.mdx
new file mode 100644
index 00000000000..65a8acfe6a2
--- /dev/null
+++ b/src/content/docs/workers/reference/module-registry.mdx
@@ -0,0 +1,328 @@
+---
+title: Module registry
+pcx_content_type: reference
+description: Configure standards-based module resolution, import.meta, Node.js module loading, lazy compilation, and shared compilation caches in Workers.
+products:
+ - workers
+sidebar:
+ order: 5
+---
+
+import { TypeScriptExample, WranglerConfig } from "~/components";
+
+The Workers runtime uses a module registry to resolve [JavaScript module specifiers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules), compile modules, and provide them to V8. A new implementation is available through the [`new_module_registry` compatibility flag](/workers/configuration/compatibility-flags/#new-module-registry).
+
+The new registry resolves specifiers as URLs rather than filesystem-style paths. This enables `import.meta` support, more predictable resolution behavior, consistent errors, and performance improvements through lazy compilation and shared caching.
+
+:::note
+
+You must add the `new_module_registry` flag explicitly. Existing Workers continue to use the original registry. Python Workers always use the original registry.
+
+:::
+
+## Turn on the new module registry
+
+Add the `new_module_registry` compatibility flag to your Wrangler configuration file:
+
+
+
+```jsonc
+{
+ "compatibility_date": "$today",
+ "compatibility_flags": ["new_module_registry"]
+}
+```
+
+
+
+## `import.meta`
+
+[`import.meta`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import.meta) exposes metadata about the current JavaScript module. JavaScript hosts define the properties available on this object.
+
+Workers provides `url`, `main`, `filename`, `dirname`, and `resolve()` when the new module registry is enabled:
+
+
+
+```ts
+const moduleMeta = import.meta as ImportMeta & {
+ readonly url: string;
+ readonly main: boolean;
+ readonly filename?: string;
+ readonly dirname?: string;
+ resolve(specifier: string): string;
+};
+
+export default {
+ async fetch() {
+ return Response.json({
+ url: moduleMeta.url,
+ main: moduleMeta.main,
+ filename: moduleMeta.filename,
+ dirname: moduleMeta.dirname,
+ resolved: moduleMeta.resolve("./utils.js"),
+ });
+ },
+};
+```
+
+
+
+### `import.meta.url`
+
+Returns the URL of the current module as a string.
+
+```js
+console.log(import.meta.url);
+// "file:///bundle/index.js"
+```
+
+### `import.meta.main`
+
+Returns `true` only for the module configured as your Worker's entrypoint. Every other module returns `false`.
+
+```js
+export default {
+ async fetch(request) {
+ return new Response(`main: ${import.meta.main}`);
+ // "main: true" for the entrypoint module
+ },
+};
+```
+
+### `import.meta.filename`
+
+Returns the absolute path of the current module without the `file:` protocol. For example, a module with the URL `file:///bundle/index.js` returns `/bundle/index.js`.
+
+This property is only available for `file:` modules. It is `undefined` for modules that use another protocol.
+
+### `import.meta.dirname`
+
+Returns the directory that contains `import.meta.filename`. For example, a module with the URL `file:///bundle/index.js` returns `/bundle`.
+
+This property is only available for `file:` modules. It is `undefined` for modules that use another protocol.
+
+### `import.meta.resolve()`
+
+[`import.meta.resolve()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import.meta/resolve) resolves a specifier against the current module without importing it. This string transformation does not check whether the resulting URL belongs to an uploaded module.
+
+```js
+import.meta.resolve("./utils.js"); // "file:///bundle/utils.js"
+import.meta.resolve("./a/../utils.js"); // "file:///bundle/utils.js"
+```
+
+With [Node.js compatibility](/workers/runtime-apis/nodejs/) enabled, the registry also recognizes bare Node.js built-ins:
+
+```js
+import.meta.resolve("fs"); // "node:fs"
+```
+
+`import.meta.resolve()` normalizes percent-encoding the same way `new URL()` does. It collapses dot segments but does not decode characters that are already percent-encoded. For example, `import.meta.resolve('%66oo.js')` resolves to `file:///bundle/%66oo.js`, not `file:///bundle/foo.js`.
+
+A `TypeError` is thrown for a specifier that cannot be parsed as a URL.
+
+## Specifiers are URLs
+
+Module specifiers are resolved as URLs using `new URL(specifier, base)`. This applies to modules that reach the Workers runtime.
+
+Wrangler bundles most JavaScript dependencies into your entrypoint by default. This removes their original module boundaries before the runtime receives your code. Built-in `node:` imports and separate WebAssembly, text, or binary modules still reach the registry. You can also use [additional modules](/workers/wrangler/bundling/#find-additional-modules) or [turn off bundling](/workers/wrangler/bundling/#disable-bundling) to upload JavaScript modules separately.
+
+Full URLs work as specifiers:
+
+```js
+import { helper } from "file:///bundle/utils.js";
+```
+
+The registry only loads modules included with your Worker or provided by the runtime. An `https:` specifier does not fetch a module over the network.
+
+### Query strings and fragments
+
+A specifier with a different query string or fragment is treated as a distinct module instance, following the same module-identity rules browsers use. Each instance gets its own `import.meta.url` and its own copy of top-level state.
+
+```js
+// counter.js
+let n = 0;
+export function increment() {
+ return ++n;
+}
+```
+
+```js
+import { increment as incA } from "./counter.js?a";
+import { increment as incB } from "./counter.js?b";
+
+incA(); // 1
+incA(); // 2
+incB(); // 1 — separate instance with its own copy of `n`
+```
+
+Importing the same specifier with the same query string returns the same instance. This does not provide a way to force re-evaluation on every import.
+
+## `node:` imports resolve consistently
+
+With [Node.js compatibility](/workers/runtime-apis/nodejs/) enabled, all paths to a `node:` built-in return the same per-isolate module instance: static `import`, dynamic `import()`, `require()`, and `process.getBuiltinModule()`.
+
+```js
+import { default as processA } from "node:process";
+
+const viaImport = await import("node:process");
+const viaBuiltin = process.getBuiltinModule("node:process");
+
+viaImport.default === processA; // true
+viaBuiltin === processA; // true
+```
+
+A given built-in is a true singleton, including any module-level state, regardless of how your code reaches it.
+
+## Import attributes
+
+The new registry validates [import attributes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import/with) correctly. `json` is the only supported attribute type:
+
+```js
+import data from "./config.json" with { type: "json" };
+```
+
+### Unsupported attribute types
+
+The `text` and `bytes` attribute types are recognized but not yet supported. They track the [Import Text](https://github.com/tc39/proposal-import-text) and [Import Bytes](https://github.com/tc39/proposal-import-bytes) TC39 proposals, which have not yet reached Stage 4. Using them produces a specific error:
+
+```js
+import msg from "./message.txt" with { type: "text" };
+// TypeError: Import attribute type "text" is not yet supported
+```
+
+### Unknown attribute keys
+
+Any attribute key other than `type` throws an error:
+
+```js
+import data from "./config.json" with { type: "json", cache: "no" };
+// TypeError: Unsupported import attribute: "cache"
+```
+
+### Type mismatches
+
+If the specified type does not match the actual module type, an error is thrown:
+
+```js
+import data from "./utils.js" with { type: "json" };
+// TypeError: Module "./utils.js" is not of type "json"
+```
+
+## `require(esm)`
+
+When `require()` is called on an ES module, the registry follows Node.js [`require(esm)`](https://nodejs.org/api/modules.html#loading-ecmascript-modules-using-require) behavior:
+
+- If the module has a string-named export called `'module.exports'`, that value is returned. This is Node.js' mechanism for letting an ES module control what `require()` returns.
+- Otherwise, `require()` returns the module's namespace object.
+- For workerd `node:` built-ins, `require()` returns the default export directly so that patterns like `require('node:buffer').Buffer` work as expected.
+
+```js
+// utils.mjs
+const impl = { hello: "world" };
+export { impl as "module.exports" };
+export default "not this";
+```
+
+```js
+import { createRequire } from "node:module";
+
+const myRequire = createRequire(import.meta.url);
+myRequire("./utils.mjs"); // { hello: "world" }
+```
+
+### Top-level `await` restriction
+
+If a module or any module in its import graph uses top-level `await`, `require()` throws an error. This matches Node.js' [`ERR_REQUIRE_ASYNC_MODULE`](https://nodejs.org/api/errors.html#err_require_async_module) restriction. Use `import()` for modules that rely on top-level `await`.
+
+```js
+// async-init.mjs
+await Promise.resolve();
+export const ready = true;
+```
+
+```js
+myRequire("./async-init.mjs");
+// Error: Top-level await is not supported in this context
+// for module: file:///bundle/async-init.mjs
+```
+
+### Bundler compatibility
+
+If a required module sets a truthy `__cjsUnwrapDefault` export (a marker used by some bundlers), the default export is returned. This ensures existing prebuilt bundles continue to work.
+
+## Error handling
+
+All module resolution errors use consistent classes and messages regardless of whether the failure occurs through a static `import`, dynamic `import()`, or `require()`:
+
+| Error | Class | Example message |
+| ---------------------------- | ----------- | ------------------------------------------ |
+| Module not found | `Error` | `Module not found: file:///bundle/nope.js` |
+| Invalid specifier | `TypeError` | `Invalid module specifier: https://` |
+| Circular dependency | `Error` | (V8 circular dependency error) |
+| Unsupported import attribute | `TypeError` | `Unsupported import attribute: "cache"` |
+
+## Lazy compilation and shared caches
+
+The new registry includes two performance improvements:
+
+### Lazy compilation
+
+Modules are not compiled until they are first imported. Statically imported dependencies compile with their module graph. Separately uploaded modules that are reached through a [dynamic `import()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import) can defer compilation until the relevant code path runs.
+
+For example, this Worker only imports and compiles `report.mjs` for requests to `/report`:
+
+```js title="src/modules/report.mjs"
+export function generateReport() {
+ return "Your report is ready";
+}
+```
+
+
+
+```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!");
+ },
+};
+```
+
+
+
+To keep `report.mjs` separate from the entrypoint, configure Wrangler to [find additional modules](/workers/wrangler/bundling/#find-additional-modules).
+
+### Shared compiled code
+
+Cloudflare can run multiple V8 isolate replicas of a Worker. The original registry compiles the bundle independently in each replica. The new registry can cache compiled JavaScript data and compiled WebAssembly modules for reuse by subsequent replicas.
+
+## WebAssembly source phase imports
+
+You can import the compiled-but-not-instantiated form of a WebAssembly module using [source phase imports](https://github.com/nicolo-ribaudo/tc39-proposal-esm-integration/blob/main/proposals/source-phase-imports.md):
+
+```js
+import source wasmModule from "./add.wasm";
+
+export default {
+ async fetch() {
+ const instance = await WebAssembly.instantiate(wasmModule, {});
+ return new Response(String(instance.exports.add(1, 2)));
+ },
+};
+```
+
+Source phase imports can also be used dynamically:
+
+```js
+const wasmModule = await import.source("./add.wasm");
+```
+
+Both forms return a `WebAssembly.Module` directly. Source phase imports are only supported for WebAssembly modules. Using them on any other module type throws a `SyntaxError`.
+
+For more information on using WebAssembly in Workers, refer to [Wasm in JavaScript](/workers/runtime-apis/webassembly/javascript/).
diff --git a/src/content/docs/workers/runtime-apis/nodejs/index.mdx b/src/content/docs/workers/runtime-apis/nodejs/index.mdx
index 5534347ae35..2938b364fe2 100644
--- a/src/content/docs/workers/runtime-apis/nodejs/index.mdx
+++ b/src/content/docs/workers/runtime-apis/nodejs/index.mdx
@@ -7,7 +7,7 @@ products:
- workers
---
-import { Render, WranglerConfig } from "~/components";
+import { Render, TypeScriptExample, WranglerConfig } from "~/components";
When you write a Worker, you may need to import packages from [npm](https://www.npmjs.com/). Many npm packages rely on APIs from the [Node.js runtime](https://nodejs.org/en/about), and will not work unless these Node.js APIs are available.
@@ -33,6 +33,50 @@ To enable built-in Node.js APIs and add polyfills, add the `nodejs_compat` compa
+### Module loading
+
+The `nodejs_compat` flag provides Node.js APIs. The separate [`new_module_registry` compatibility flag](/workers/configuration/compatibility-flags/#new-module-registry) provides Node.js-compatible module-loading behavior.
+
+Enable both flags to use [`createRequire()`](https://nodejs.org/api/module.html#modulecreaterequirefilename) with `import.meta.url`, load ES modules through [`require()`](https://nodejs.org/api/modules.html#loading-ecmascript-modules-using-require), and receive the same built-in module instance through different loading APIs:
+
+
+
+```jsonc
+{
+ "compatibility_date": "$today",
+ "compatibility_flags": ["nodejs_compat", "new_module_registry"]
+}
+```
+
+
+
+
+
+```ts
+import { createRequire } from "node:module";
+import process from "node:process";
+
+const moduleMeta = import.meta as ImportMeta & {
+ readonly url: string;
+ resolve(specifier: string): string;
+};
+const require = createRequire(moduleMeta.url);
+const requiredProcess = require("node:process");
+
+export default {
+ async fetch() {
+ return Response.json({
+ sameInstance: requiredProcess === process,
+ resolved: moduleMeta.resolve("process"),
+ });
+ },
+};
+```
+
+
+
+For resolution rules and CommonJS interoperability, refer to the [module registry reference](/workers/reference/module-registry/#requireesm).
+
## Supported Node.js APIs
The runtime APIs from Node.js listed in this section with the status "🟢 supported" are currently natively supported in the Workers Runtime. Items listed as "🟡 partially supported" include usable APIs, but do not implement the complete Node.js API surface.
@@ -63,7 +107,7 @@ The runtime APIs from Node.js listed in this section with the status "🟢 suppo
| [Process](/workers/runtime-apis/nodejs/process/) | 🟢 supported |
| [Punycode](https://nodejs.org/docs/latest/api/punycode.html) (deprecated) | 🟢 supported |
| [Query strings](https://nodejs.org/docs/latest/api/querystring.html) | 🟢 supported |
-| [Stream](/workers/runtime-apis/nodejs/streams/) | 🟢 supported |
+| [Stream](/workers/runtime-apis/nodejs/streams/) | 🟢 supported |
| [String decoder](/workers/runtime-apis/nodejs/string-decoder/) | 🟢 supported |
| [Test runner](/workers/runtime-apis/nodejs/test/) | 🟡 partially supported |
| [Timers](/workers/runtime-apis/nodejs/timers/) | 🟢 supported |
diff --git a/src/content/docs/workers/runtime-apis/web-standards.mdx b/src/content/docs/workers/runtime-apis/web-standards.mdx
index 266fba039da..c15ad84be1c 100644
--- a/src/content/docs/workers/runtime-apis/web-standards.mdx
+++ b/src/content/docs/workers/runtime-apis/web-standards.mdx
@@ -9,6 +9,8 @@ products:
- workers
---
+import { TypeScriptExample } from "~/components";
+
## JavaScript standards
The Cloudflare Workers runtime is [built on top of the V8 JavaScript and WebAssembly engine](/workers/reference/how-workers-works/). The Workers runtime is updated at least once a week, to at least the version of V8 that is currently used by Google Chrome's stable release. This means you can safely use the latest JavaScript features, with no need for transpilers.
@@ -24,6 +26,36 @@ All of the [standard built-in objects](https://developer.mozilla.org/en-US/docs/
- [`WebAssembly.instantiateStreaming`](https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/instantiateStreaming_static)
- `Date.now()` returns the time of the last I/O; it does not advance during code execution.
+### `import.meta`
+
+JavaScript hosts define the properties available through [`import.meta`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import.meta). With the [`new_module_registry` compatibility flag](/workers/configuration/compatibility-flags/#new-module-registry), Workers provides `import.meta.url`, `import.meta.main`, `import.meta.filename`, `import.meta.dirname`, and [`import.meta.resolve()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import.meta/resolve).
+
+Use these properties to inspect the current module or resolve another module without importing it:
+
+
+
+```ts
+const moduleMeta = import.meta as ImportMeta & {
+ readonly url: string;
+ readonly main: boolean;
+ resolve(specifier: string): string;
+};
+
+export default {
+ async fetch() {
+ return Response.json({
+ currentModule: moduleMeta.url,
+ isEntrypoint: moduleMeta.main,
+ dependency: moduleMeta.resolve("./dependency.js"),
+ });
+ },
+};
+```
+
+
+
+For property behavior and module-loading details, refer to the [`import.meta` module registry reference](/workers/reference/module-registry/#importmeta).
+
---
## Web standards and global APIs
@@ -34,7 +66,6 @@ The following methods are available per the [Worker Global Scope](https://develo
- atob()
- Decodes a string of data which has been encoded using base-64 encoding.
-
- btoa()
- Creates a base-64 encoded ASCII string from a string of binary data.
@@ -42,16 +73,12 @@ The following methods are available per the [Worker Global Scope](https://develo
- setInterval()
- Schedules a function to execute every time a given number of milliseconds elapses.
-
- clearInterval()
- Cancels the repeated execution set using [`setInterval()`](https://developer.mozilla.org/en-US/docs/Web/API/setInterval).
-
- setTimeout()
- Schedules a function to execute in a given amount of time.
-
- clearTimeout()
- Cancels the delayed execution set using [`setTimeout()`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout).
-
- [`scheduler.wait()`](/workers/runtime-apis/scheduler/)
- Returns a Promise that resolves after a given number of milliseconds. An `await`-able alternative to `setTimeout()`.
@@ -65,7 +92,6 @@ Timers are only available inside of [the Request Context](/workers/runtime-apis/
- performance.timeOrigin
- Returns the high resolution time origin. Workers uses the UNIX epoch as the time origin, meaning that `performance.timeOrigin` will always return `0`.
-
- performance.now()
- Returns a `DOMHighResTimeStamp` representing the number of milliseconds elapsed since `performance.timeOrigin`. Note that Workers intentionally reduces the precision of `performance.now()` such that it returns the time of the last I/O and does not advance during code execution. Effectively, because of this, and because `performance.timeOrigin` is always, `0`, `performance.now()` will always equal `Date.now()`, yielding a consistent view of the passage of time within a Worker.
diff --git a/src/content/docs/workers/runtime-apis/webassembly/javascript.mdx b/src/content/docs/workers/runtime-apis/webassembly/javascript.mdx
index 352855c7310..53c9c31404c 100644
--- a/src/content/docs/workers/runtime-apis/webassembly/javascript.mdx
+++ b/src/content/docs/workers/runtime-apis/webassembly/javascript.mdx
@@ -86,6 +86,26 @@ export default {
When invoked, this Worker should log `Hello from JavaScript: 42` and return `Success: 42`, demonstrating the ability to invoke Wasm methods with arguments from JavaScript and vice versa.
+## Source phase imports
+
+With the [`new_module_registry`](/workers/configuration/compatibility-flags/#new-module-registry) compatibility flag, you can import a compiled-but-not-instantiated `WebAssembly.Module` directly using source phase imports:
+
+```js
+import source wasmModule from "./simple.wasm";
+
+const instance = await WebAssembly.instantiate(wasmModule, {});
+```
+
+Source phase imports can also be used dynamically:
+
+```js
+const wasmModule = await import.source("./simple.wasm");
+```
+
+Both forms return a `WebAssembly.Module`. Source phase imports are only supported for WebAssembly modules. Using them on any other module type throws a `SyntaxError`.
+
+For more information, refer to [WebAssembly source phase imports](/workers/reference/module-registry/#webassembly-source-phase-imports).
+
## Next steps
In practice, you will likely compile a language of your choice (such as Rust) to WebAssembly binaries. Many languages provide a `bindgen` to simplify the interaction between JavaScript and Wasm. These tools may integrate with your JavaScript bundler, and provide an API other than the WebAssembly API for initializing and invoking your Wasm module. As an example, refer to the [Rust `wasm-bindgen` documentation](https://wasm-bindgen.github.io/wasm-bindgen/examples/without-a-bundler.html).