> For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt.

# Experiments

Enables experimental features.

- **Type:** `object`

:::tip
In minor releases, Rspack may change the APIs of experimental features. If you're using experimental features, pay attention to the minor release notes for detailed explanations of changes.
:::

## experiments.asyncWebAssembly

- **Type:** `boolean`
- **Default:** `true`

Supports the new WebAssembly according to the [updated specification](https://github.com/WebAssembly/esm-integration), making WebAssembly modules async.

```js title="rspack.config.mjs"
export default {
  experiments: {
    asyncWebAssembly: true,
  },
};
```

## experiments.buildHttp


[Added in v1.3.0](https://github.com/web-infra-dev/rspack/releases/tag/v1.3.0)

- **Type:** `HttpUriOptions`
- **Default:** `undefined`

```ts
type HttpUriOptions = {
  /**
   * A list of allowed URIs
   */
  allowedUris: (string | RegExp)[];
  /**
   * Define the location to store the lockfile
   */
  lockfileLocation?: string;
  /**
   * Define the location for caching remote resources
   */
  cacheLocation?: string | false;
  /**
   * Detect changes to remote resources and upgrade them automatically
   * @default false
   */
  upgrade?: boolean;
  /**
   * Freeze the remote resources and lockfile
   * @default true in production mode, false otherwise
   */
  frozen?: boolean;
  /**
   * Custom http client
   */
  httpClient?: (
    url: string,
    headers: Record<string, string>,
  ) => Promise<{
    status: number;
    headers: Record<string, string>;
    body: Buffer;
  }>;
};
```

After enabling this feature, Rspack can build remote resources that start with the `http(s):` protocol. Rspack will download the resources to the local machine and then bundle them.

String entries in `allowedUris` must be valid absolute URLs. Rspack normalizes both the requested URL and each string entry before comparing their prefixes. For example, `'https://example.com'` is normalized to `'https://example.com/'`. Invalid string entries, such as `'https://'`, are ignored. Regular expressions are tested against the normalized URL; use `/^https:\/\//` if you intend to allow any HTTPS URL. Redirect targets must also match `allowedUris`.

By default, Rspack will generate `rspack.lock` and `rspack.lock.data` in the [context](/config/context.md) folder as the locations of the Lockfile and the cache respectively. You can also configure them through `lockfileLocation` and `cacheLocation`.

:::note
You should commit the files at `lockfileLocation` and `cacheLocation` to the version control system so that production builds can use the cached content.
:::

Rspack checks cached content against the SHA-512 integrity recorded in the lockfile. `frozen` defaults to `true` in production mode and `false` otherwise. When frozen, missing lockfile entries, corrupted cached content, missing cache files, and changes to a resource's content, resolved URL, or content type cause a build error. The lockfile and its content cache are not updated. With `cacheLocation: false`, downloaded content must still match the locked entry.

Older lockfiles may record a redirected import only under its final URL. If the original URL has no entry, a frozen build makes network requests to follow allowed redirects until it finds an existing locked entry, then verifies its content without rewriting the lockfile or cache. Imports that do not reach a locked resource still fail. If the original URL already has an entry, that entry remains authoritative.

To populate the lockfile and cache, run a development build or explicitly set `frozen: false`. To check for remote updates, also set `upgrade: true`, then review and commit the resulting changes. `upgrade: false` prefers cached content; it does not prevent lockfile updates when content must be downloaded. An unfrozen build can also repair the lockfile to accept locally edited cache files, matching webpack's behavior.

Resources recorded as `"no-cache"` or `"ignore"` are fetched without pinning their content, including in frozen mode. Integrity checks rely on a trusted lockfile and do not authenticate the first download. To prevent Git from changing the cached bytes' line endings, add `**/*rspack.lock.data/** -text` to `.gitattributes`, adapting the pattern if you use a custom cache location.

For example:

```js title="rspack.config.mjs"
import path from 'node:path';

export default {
  experiments: {
    buildHttp: {
      allowedUris: ['https://example.com/'],
      lockfileLocation: path.join(import.meta.dirname, 'my_project.lock'),
      cacheLocation: path.join(import.meta.dirname, 'my_project.lock.data'),
    },
  },
};
```

With this feature enabled, you can import modules directly from URLs:

```js
// Import from a remote URL
import { something } from 'https://example.com/module.js';

// Or import assets
import imageUrl from 'https://example.com/image.png';
```

## experiments.deferImport


[Added in v1.6.0](https://github.com/web-infra-dev/rspack/releases/tag/v1.6.0)

- **Type:** `boolean`
- **Default:** `false`

When enabled, Rspack will support bundling the [Deferred Imports Evaluation](https://github.com/tc39/proposal-defer-import-eval) proposal, which allows deferring the evaluation of a module until its first use. Rspack supports both `import defer * as ns from "./module"` and `import.defer()` syntax.

```js title="rspack.config.mjs"
export default {
  experiments: {
    deferImport: true,
  },
};
```

:::info Known Limitation
Currently, when using `output.module: true`, `defer import` syntax for external modules will be compiled to standard `import` syntax.

For example, if `jquery` is configured as external:

```js
import defer * as $ from 'jquery';
```

It will generate:

```js
import * as __rspack_external_jquery from 'jquery';
```

This is because `defer import` syntax is not yet supported by any runtime. In the future, Rspack will support preserving `defer import` syntax based on the target configuration, generating the following code:

```js
import defer * as __rspack_external_jquery from 'jquery';
```

:::

## experiments.sourceImport


[Added in v2.0.8](https://github.com/web-infra-dev/rspack/releases/tag/v2.0.8)

Stability: Experimental

- **Type:** `boolean`
- **Default:** `false`

Enables support for the TC39 [Source Phase Imports](https://github.com/tc39/proposal-source-phase-imports) proposal.

Source phase imports let you import a module before it is evaluated. In Rspack, this support is currently designed for WebAssembly modules: importing a `.wasm` module in the source phase returns a compiled [`WebAssembly.Module`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Module), so you can instantiate it yourself, instantiate it more than once with different imports, or transfer it to a worker.

Enable `experiments.sourceImport`:

```js title="rspack.config.mjs"
export default {
  experiments: {
    sourceImport: true,
  },
};
```

You can use the static source-phase syntax:

```js
import source wasmModule from './module.wasm';

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

Or the dynamic syntax:

```js
const wasmModule = await import.source('./module.wasm');
const instance = await WebAssembly.instantiate(wasmModule);
```

:::note
For a normal WebAssembly import, Rspack instantiates the module and exposes its exports. For a source phase import, Rspack returns the compiled `WebAssembly.Module` instead, and your code is responsible for calling `WebAssembly.instantiate`.
:::

## experiments.futureDefaults

- **Type:** `boolean`
- **Default:** `false`

Uses defaults from the next major Rspack version and shows warnings for any problematic configuration.

```js title="rspack.config.mjs"
export default {
  experiments: {
    futureDefaults: true,
  },
};
```

## experiments.nativeWatcher


[Added in v1.4.7](https://github.com/web-infra-dev/rspack/releases/tag/v1.4.7)

- **Type:** `boolean`
- **Default:** `false`

By default, Rspack uses Watchpack to monitor file changes, which generally works well in most scenarios.
However, in certain specific environments, issues may arise. For example, Watchpack may experience performance problems when there are a large number of file changes.
More detail see: [Watchpack issue #223](https://github.com/webpack/watchpack/issues/223).

If you encounter performance issues with the default watcher, you can try enabling nativeWatcher.

After enabling `nativeWatcher`, Rspack will use the Rust Native file system to monitor file changes, enabling incremental file change detection, which provides better performance and stability.

```js title="rspack.config.mjs"
export default {
  watchOptions: {
    // Other watch options...
  },
  experiments: {
    nativeWatcher: true,
  },
};
```

## experiments.pureFunctions


[Added in v2.0.0](https://github.com/web-infra-dev/rspack/releases/tag/v2.0.0)

- **Type:** `boolean`
- **Default:** `true` in production mode, `false` otherwise

Enables cross-module side-effect-free function call optimization, including the `/*#__NO_SIDE_EFFECTS__*/` annotation and [`module.parser.javascript.pureFunctions`](/config/module-parser.md#javascriptpurefunctions). Functions marked through annotations or user configuration are omitted from the output when they are not actually used.

For more background, see [pureFunctions](/guide/optimization/tree-shaking.md#purefunctions) and [NO\_SIDE\_EFFECTS annotation](/guide/optimization/tree-shaking.md#no_side_effects-annotation).

This capability is enabled by default in production mode. To disable pure-function analysis, set this option to `false`. To manually mark identifiers in matched modules — exported functions in a third-party module, or imports/locals in your own files — configure [`module.parser.javascript.pureFunctions`](/config/module-parser.md#javascriptpurefunctions) through `module.rules[i].parser` so the rule only applies to the intended modules.

```js title="rspack.config.mjs"
export default {
  experiments: {
    pureFunctions: true,
  },
  module: {
    rules: [
      {
        test: /node_modules\/some-library\/index\.js$/,
        parser: {
          pureFunctions: ['isString'],
        },
      },
    ],
  },
};
```

:::warning
This option depends on `optimization.sideEffects`. If you disable [`optimization.sideEffects`](/config/optimization.md#optimizationsideeffects), pure-function hints will not be analyzed.
:::

## experiments.runtimeMode


[Added in v2.2.0](https://github.com/web-infra-dev/rspack/releases/tag/v2.2.0)

- **Type:** `'webpack' | 'rspack'`
- **Default:** `'webpack'`

Setting `experiments.runtimeMode` to `'rspack'` enables Rspack's experimental runtime output. This output mode is still under development, so use it with caution. It currently generates cleaner output when [`output.module`](/config/output.md#outputmodule) is `true` and [`output.library.type`](/config/output.md#outputlibrarytype) is `'modern-module'`. In this case, instead of exporting one `__webpack_require__` function with runtime helpers attached as properties, the runtime exports the loader, module factories, and helpers as named ESM bindings. Each output chunk can import only the bindings it needs.

### Example

```js title="rspack.config.mjs"
export default {
  experiments: {
    runtimeMode: 'rspack',
  },
  output: {
    module: true,
    library: {
      type: 'modern-module',
    },
  },
  optimization: {
    runtimeChunk: 'single',
  },
};
```

The generated runtime and a chunk that consumes it are organized like this (simplified):


**runtimeMode: 'webpack'**

```js
// runtime.js
var __webpack_modules__ = {};
function __webpack_require__(moduleId) {
  /* ... */
}
__webpack_require__.m = __webpack_modules__;
__webpack_require__.n = (module) => {
  /* ... */
};

export { __webpack_require__ };

// main.js
import { __webpack_require__ } from './runtime.js';

const value = __webpack_require__(moduleId);
const getDefault = __webpack_require__.n(value);
```


**runtimeMode: 'rspack'**

```js
// runtime.js
var modules = {};
function rspackRequire(moduleId) {
  /* ... */
}
var moduleFactories = modules;
var compatGetDefaultExport = (module) => {
  /* ... */
};

export { rspackRequire, moduleFactories, compatGetDefaultExport };

// main.js
import { rspackRequire, compatGetDefaultExport } from './runtime.js';

const value = rspackRequire(moduleId);
const getDefault = compatGetDefaultExport(value);
```


## experiments.useInputFileSystem


[Added in v1.3.14](https://github.com/web-infra-dev/rspack/releases/tag/v1.3.14)

- **Type:** `false | RegExp[]`
- **Default:** `false`

By default, Rspack reads files from disk using a native file system.
However, it is possible to change the file system using a different kind of file system.
To accomplish this, one can change the inputFileSystem. For example, you can replace the default inputFileSystem with memfs to virtual Modules.

But due to the overheads calling file system implemented in Node.js side, it will slow down Rspack a lot.
So we make a trade off by providing the `useInputFileSystem` config, to tell rspack to read file from the native file system or from modified inputFileSystem.

In below example, you can simply replace the default input file system to any file system satisfied the [`InputFileSystem`](/api/javascript-api/compiler.md#inputfilesystem-1) interface.

:::info Note
The replacing of `compiler.inputFileSystem` will only take effect before `compiler.run` called; Replacing after `compiler.run` will not take effect.
:::

More detailed case can be found [here](https://github.com/web-infra-dev/rspack/tree/main/tests/rspack-test/configCases/input-file-system/rspack.config.js)

```js title="rspack.config.mjs"
export default {
  entry: {
    index: './virtual_index.js',
  },
  plugins: [
    {
      apply: (compiler) => {
        compiler.hooks.beforeCompile.tap('SimpleInputFileSystem', () => {
          compiler.inputFileSystem = {
            readFile(path, cb) {
              cb(null, `// the file content`);
            },
            stat(p, cb) {
              cb(null, fsState);
            },
          };
        });
      },
    },
  ],
  experiments: {
    useInputFileSystem: [/virtual_.*\.js/],
  },
};
```

### Work with webpack-virtual-modules

```js title="rspack.config.mjs"
import VirtualModulesPlugin from 'webpack-virtual-modules';

const virtualModules = new VirtualModulesPlugin({
  'virtual-entry.js': `
    import "./src/another-virtual.js";
    import "./src/disk-file.js";
    `,
  'src/another-virtual.js': 'export default 42;',
});

export default {
  entry: './virtual-entry.js',
  plugins: [virtualModules],
  experiments: {
    useInputFileSystem: [/.*virtual.*\.js$/],
  },
};
```

When access to `virtual-entry.js` and `src/another-virtual.js` which match the regular expressions of `experiments.useInputFileSystem`,
Rspack will use the input file system wrapped by `VirtualModulesPlugin`; other than that, `src/disk-file.js` will be accessed by the native file system.


This page is adapted from [webpack documentation](https://webpack.js.org/configuration/experiments/) under the [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), with modifications.

