From a733a6d79ec1da7814a3123f23214ea1469e8d82 Mon Sep 17 00:00:00 2001
From: alexander-akait <4567934+alexander-akait@users.noreply.github.com>
Date: Tue, 8 Sep 2026 10:55:06 +0000
Subject: [PATCH] docs: mark experiments.outputModule removed, document
output.module alone
ESM output is stable in webpack 5.111.0, so `output.module` no longer
needs an experiment behind it.
---
src/content/blog/2026-06-25-webpack-5-108.mdx | 2 +-
src/content/configuration/experiments.mdx | 17 +------------
src/content/configuration/externals.mdx | 14 +++++------
src/content/configuration/output.mdx | 25 ++++++-------------
src/content/configuration/performance.mdx | 1 -
src/content/configuration/target.mdx | 6 ++---
src/content/guides/modern-web-platform.mdx | 7 ++----
src/content/guides/native-html.mdx | 2 +-
8 files changed, 23 insertions(+), 51 deletions(-)
diff --git a/src/content/blog/2026-06-25-webpack-5-108.mdx b/src/content/blog/2026-06-25-webpack-5-108.mdx
index 47306006c8b6..cc3fd4a309c1 100644
--- a/src/content/blog/2026-06-25-webpack-5-108.mdx
+++ b/src/content/blog/2026-06-25-webpack-5-108.mdx
@@ -54,7 +54,7 @@ module.exports = {
[`target: "universal"`](/configuration/target/#universal) combines the `web`, `web worker`, `node`, `electron`, and `nwjs` platforms into one target and leaves each platform flag _neutral_ instead of locking the bundle to a single environment. Rather than compiling separate web and node bundles, you ship one bundle that figures out its surroundings at runtime and uses whatever the current platform provides.
-A bundle that has to load equally well in a browser and in Node needs a portable module format, so universal builds always output ECMAScript modules: [`experiments.outputModule`](/configuration/experiments/#experimentsoutputmodule) defaults to `true`, synchronous `require` is turned off, and Node's built-in modules stay available (resolved at runtime through ESM). [`output.globalObject`](/configuration/output/#outputglobalobject) also defaults to `globalThis` so runtime code has one global to reach for on every platform.
+A bundle that has to load equally well in a browser and in Node needs a portable module format, so universal builds always output ECMAScript modules: [`output.module`](/configuration/output/#outputmodule) defaults to `true`, synchronous `require` is turned off, and Node's built-in modules stay available (resolved at runtime through ESM). [`output.globalObject`](/configuration/output/#outputglobalobject) also defaults to `globalThis` so runtime code has one global to reach for on every platform.
To make a single bundle behave correctly everywhere, several pieces were made platform-aware and now branch on feature detection at runtime instead of being fixed at build time:
diff --git a/src/content/configuration/experiments.mdx b/src/content/configuration/experiments.mdx
index 21fd57198950..e14ad9fbe8fc 100644
--- a/src/content/configuration/experiments.mdx
+++ b/src/content/configuration/experiments.mdx
@@ -29,10 +29,10 @@ Available options:
- [`futureDefaults`](#experimentsfuturedefaults)
- [`html`](#experimentshtml)
- [`lazyCompilation`](#experimentslazycompilation)
-- [`outputModule`](#experimentsoutputmodule)
- [`typescript`](#experimentstypescript)
- [`sourceImport`](#experimentssourceimport)
- `syncWebAssembly`: Support the old WebAssembly like in webpack 4.
+- `outputModule`: Output ECMAScript module syntax wherever possible, removed since `5.111.0` — set [`output.module`](/configuration/output/#outputmodule) to `true` instead, it no longer needs an experiment.
- `layers`: Enable module and chunk layers, removed and works without additional options since `5.102.0`.
- `topLevelAwait`: Transforms a module into an `async` module when an `await` is used at the top level. Starting from webpack version `5.83.0` (however, in versions prior to that, you can enable it by setting `experiments.topLevelAwait` to `true`), this feature is enabled by default, removed and works without additional options since `5.102.0`.
@@ -45,7 +45,6 @@ export default {
asyncWebAssembly: true,
buildHttp: true,
lazyCompilation: true,
- outputModule: true,
sourceImport: true,
syncWebAssembly: true,
topLevelAwait: true,
@@ -606,20 +605,6 @@ Compile entrypoints and dynamic `import`s only when they are in use. It can be u
};
```
-### experiments.outputModule
-
-`boolean`
-
-Once enabled, webpack will output ECMAScript module syntax whenever possible. For instance, `import()` to load chunks, ESM exports to expose chunk data, among others.
-
-```js
-export default {
- experiments: {
- outputModule: true,
- },
-};
-```
-
### experiments.typescript
diff --git a/src/content/configuration/externals.mdx b/src/content/configuration/externals.mdx
index b7318bbf0a6c..b75118c97059 100644
--- a/src/content/configuration/externals.mdx
+++ b/src/content/configuration/externals.mdx
@@ -546,7 +546,7 @@ jq(".my-element").animate(/* ... */);
Specify the default type of externals as `'module'`. Webpack will generate code like `import * as X from '...'` for externals used in a module.
-Make sure to enable [`experiments.outputModule`](/configuration/experiments/#experimentsoutputmodule) first, otherwise webpack will throw errors.
+Make sure to enable [`output.module`](/configuration/output/#outputmodule) first, otherwise webpack will throw errors.
#### Example
@@ -560,8 +560,8 @@ jq(".my-element").animate(/* ... */);
```js
export default {
- experiments: {
- outputModule: true,
+ output: {
+ module: true,
},
externalsType: "module",
externals: {
@@ -670,7 +670,7 @@ const src = await import.source("external-mod");
Specify the default type of externals as `'module-import'`. This combines [`'module'`](#externalstypemodule) and [`'import'`](#externalstypeimport). Webpack will automatically detect the type of import syntax, setting it to `'module'` for static imports and `'import'` for dynamic imports.
-Ensure to enable [`experiments.outputModule`](/configuration/experiments/#experimentsoutputmodule) first if static imports exist, otherwise, webpack will throw errors.
+Ensure to enable [`output.module`](/configuration/output/#outputmodule) first if static imports exist, otherwise, webpack will throw errors.
#### Example
@@ -752,8 +752,8 @@ jq(".my-element").animate(/* ... */);
```js
module.export = {
- experiments: {
- outputModule: true,
+ output: {
+ module: true,
},
externalsType: "node-commonjs",
externals: {
@@ -790,7 +790,7 @@ You can use `node-commonjs` to ensure that the prototype chain is preserved:
const { builtinModules } = require("node:module");
export default {
- experiments: { outputModule: true },
+ output: { module: true },
externalsType: "node-commonjs",
externals: ({ request }, callback) => {
if (request.startsWith("node:") || builtinModules.includes(request)) {
diff --git a/src/content/configuration/output.mdx b/src/content/configuration/output.mdx
index 651fa4bd429b..8e7231c138a3 100644
--- a/src/content/configuration/output.mdx
+++ b/src/content/configuration/output.mdx
@@ -1812,10 +1812,8 @@ These options will result in a bundle that comes with a complete header to ensur
```js
export default {
// …
- experiments: {
- outputModule: true,
- },
output: {
+ module: true,
library: {
// do not specify a `name` here
type: "module",
@@ -1824,9 +1822,7 @@ export default {
};
```
-Output ES Module.
-
-However this feature is still experimental and not fully supported yet, so make sure to enable [experiments.outputModule](/configuration/experiments/) beforehand. In addition, you can track the development progress in [this thread](https://github.com/webpack/webpack/issues/2933#issuecomment-774253975).
+Output ES Module. You can track the remaining development progress in [this thread](https://github.com/webpack/webpack/issues/2933#issuecomment-774253975).
##### type: 'modern-module'
@@ -1835,10 +1831,8 @@ However this feature is still experimental and not fully supported yet, so make
```js
export default {
// …
- experiments: {
- outputModule: true,
- },
output: {
+ module: true,
library: {
// do not specify a `name` here
type: "modern-module",
@@ -1849,8 +1843,6 @@ export default {
This configuration generates tree-shakable output for ES Modules.
-However this feature is still experimental and not fully supported yet, so make sure to enable [experiments.outputModule](/configuration/experiments/) beforehand.
-
##### type: 'commonjs2'
```js
@@ -2452,7 +2444,7 @@ These options will result in a bundle that comes with a complete header to ensur
W> Prefer to use [`output.library.type: 'module'`](#type-module).
-Output ES Module. Make sure to enable [experiments.outputModule](/configuration/experiments/) beforehand.
+Output ES Module. Make sure to enable [`output.module`](#outputmodule) beforehand.
Note that this feature is not fully supported yet, please track the progress in [this thread](https://github.com/webpack/webpack/issues/2933#issuecomment-774253975).
@@ -2677,7 +2669,7 @@ The dependencies for your library will be defined by the [`externals`](/configur
`boolean = false`
-Output JavaScript files as module type. Disabled by default as it's an experimental feature.
+Output JavaScript files as module type. It defaults to `true` for the [`universal`](/configuration/target/#universal), [`deno`](/configuration/target/#deno) and [`bun`](/configuration/target/#bun) targets, which only run ECMAScript modules, and to `false` everywhere else.
When enabled, webpack will set [`output.iife`](#outputiife) to `false`, [`output.scriptType`](#outputscripttype) to `'module'` and `minimizerOptions.module` to `true` internally.
@@ -2686,16 +2678,15 @@ If you're using webpack to compile a library to be consumed by others, make sure
```js
export default {
// ...
- experiments: {
- outputModule: true,
- },
output: {
module: true,
},
};
```
-W> `output.module` is an experimental feature and can only be enabled by setting [`experiments.outputModule`](/configuration/experiments/#experiments) to `true`. [One of the known problems](https://github.com/webpack/webpack/issues/11277#issuecomment-992565287) is that such a library can't be consumed by webpack4-based (and possibly other too) applications.
+T> Until webpack `5.111.0` this option also required [`experiments.outputModule`](/configuration/experiments/); that experiment has been removed and `output.module` now works on its own.
+
+W> [One of the known problems](https://github.com/webpack/webpack/issues/11277#issuecomment-992565287) is that such a library can't be consumed by webpack4-based (and possibly other too) applications.
## output.path
diff --git a/src/content/configuration/performance.mdx b/src/content/configuration/performance.mdx
index 08021fecd8c3..b380aa0d83d9 100644
--- a/src/content/configuration/performance.mdx
+++ b/src/content/configuration/performance.mdx
@@ -109,7 +109,6 @@ What each reason means, and what lifts it:
```js
export default {
// ...
- experiments: { outputModule: true },
output: { module: true },
performance: {
hints: "warning",
diff --git a/src/content/configuration/target.mdx b/src/content/configuration/target.mdx
index b252e3b2e5ce..a3d3045eb6eb 100644
--- a/src/content/configuration/target.mdx
+++ b/src/content/configuration/target.mdx
@@ -80,7 +80,7 @@ Supported browserslist values:
-A single preset that combines the `web`, `web worker`, `node`, `electron` and `nwjs` platforms, leaving each platform flag neutral so the bundle adapts at runtime instead of being locked to one environment. It is a convenient replacement for hand-writing `target: ["web", "node"]`, and it always outputs ECMAScript modules. [`experiments.outputModule`](/configuration/experiments/#experimentsoutputmodule) defaults to `true` for this target.
+A single preset that combines the `web`, `web worker`, `node`, `electron` and `nwjs` platforms, leaving each platform flag neutral so the bundle adapts at runtime instead of being locked to one environment. It is a convenient replacement for hand-writing `target: ["web", "node"]`, and it always outputs ECMAScript modules. [`output.module`](/configuration/output/#outputmodule) defaults to `true` for this target.
**webpack.config.js**
@@ -101,7 +101,7 @@ Notes for universal builds:
-Compile for [Bun](https://bun.sh/). The bundle is emitted as ECMAScript modules ([`experiments.outputModule`](/configuration/experiments/#experimentsoutputmodule) defaults to `true`), and Bun's own `bun:*` modules together with the Node.js built-in modules Bun provides are externalized instead of being bundled.
+Compile for [Bun](https://bun.sh/). The bundle is emitted as ECMAScript modules ([`output.module`](/configuration/output/#outputmodule) defaults to `true`), and Bun's own `bun:*` modules together with the Node.js built-in modules Bun provides are externalized instead of being bundled.
**webpack.config.js**
@@ -116,7 +116,7 @@ export default {
-Compile for [Deno](https://deno.com/). The bundle is emitted as ECMAScript modules ([`experiments.outputModule`](/configuration/experiments/#experimentsoutputmodule) defaults to `true`). Node.js built-ins are resolved through the `node:` specifier Deno requires, and Deno's own import protocols (`npm:`, `jsr:`, `node:` and `http(s)://` URLs) are kept external so the runtime loads them. A version may be specified, for example `deno2` or `deno1.40`.
+Compile for [Deno](https://deno.com/). The bundle is emitted as ECMAScript modules ([`output.module`](/configuration/output/#outputmodule) defaults to `true`). Node.js built-ins are resolved through the `node:` specifier Deno requires, and Deno's own import protocols (`npm:`, `jsr:`, `node:` and `http(s)://` URLs) are kept external so the runtime loads them. A version may be specified, for example `deno2` or `deno1.40`.
**webpack.config.js**
diff --git a/src/content/guides/modern-web-platform.mdx b/src/content/guides/modern-web-platform.mdx
index c2532d0a0388..8e8bddc88e87 100644
--- a/src/content/guides/modern-web-platform.mdx
+++ b/src/content/guides/modern-web-platform.mdx
@@ -70,7 +70,7 @@ Splitting alone does not change **browser** rules: the tag name must still be re
### Approach
-Enable [ES module output](/configuration/output/#outputmodule) (`experiments.outputModule` and `output.module`), set [`externalsType: "module"`](/configuration/externals/#externalstypemodule) for static imports, and list each bare specifier in `externals` with the same string the browser will resolve via the import map.
+Enable [ES module output](/configuration/output/#outputmodule) (`output.module`), set [`externalsType: "module"`](/configuration/externals/#externalstypemodule) for static imports, and list each bare specifier in `externals` with the same string the browser will resolve via the import map.
**webpack.config.js**
@@ -83,9 +83,6 @@ const __dirname = path.dirname(__filename);
export default {
mode: "production",
- experiments: {
- outputModule: true,
- },
entry: "./src/index.js",
externalsType: "module",
externals: {
@@ -131,7 +128,7 @@ The key `"lodash-es"` must match both the **`externals` key** and the **specifie
```
-W> [`experiments.outputModule`](/configuration/experiments/#experimentsoutputmodule) and [`output.module`](/configuration/output/#outputmodule) are still experimental. Check the latest [webpack release notes](https://github.com/webpack/webpack/releases) before relying on them in production.
+W> Check the latest [webpack release notes](https://github.com/webpack/webpack/releases) for the current state of [`output.module`](/configuration/output/#outputmodule) before relying on it in production.
### Limitations and future work
diff --git a/src/content/guides/native-html.mdx b/src/content/guides/native-html.mdx
index 3cd3930b1ef6..9c39cf61dc42 100644
--- a/src/content/guides/native-html.mdx
+++ b/src/content/guides/native-html.mdx
@@ -1093,7 +1093,7 @@ A `UrlHintRule` — used by `output.resourceHints.urlHints` and by every parser'
```js
export default {
- experiments: { html: true, outputModule: true },
+ experiments: { html: true },
output: {
module: true,
resourceHints: {