Node APIs in browser extensions

Use browser-native APIs first, then selectively polyfill Node modules only when you explicitly need them.

Extension.js targets the browser runtime by default, so Node core modules are not automatically polyfilled.

When Node polyfills are a good fit

  • A required dependency needs Node core modules in browser runtime.
  • You are incrementally migrating code from Node-centric packages.
  • You can accept larger bundles for specific runtime capabilities.

Template examples

new-typescript

new-typescript template screenshot

Start from a TypeScript baseline when your extension needs explicit bundler/polyfill tuning.

npm
pnpm
yarn
npx extension@latest create my-extension --template=new-typescript

Repository: extension-js/examples/new-typescript

content-typescript

content-typescript template screenshot

Use a content-script TypeScript base when Node-dependent libraries run inside page-injected flows.

npm
pnpm
yarn
npx extension@latest create my-extension --template=content-typescript

Repository: extension-js/examples/content-typescript

Default behavior

  • Build target is browser-first (web).
  • Resolution prioritizes browser exports (browser, module, main).
  • Node core fallbacks such as crypto, path, and fs are disabled by default.

This means importing Node APIs may fail unless you add explicit fallbacks.

Setting up Node polyfills

Use extension.config.js (or .mjs / .cjs) to extend the Rspack config and define safe fallbacks.

import NodePolyfillPlugin from "node-polyfill-webpack-plugin";
import { createRequire } from "node:module";

const require = createRequire(import.meta.url);

export default {
  config: (config) => {
    config.resolve = config.resolve || {};
    config.resolve.fallback = {
      ...(config.resolve.fallback || {}),
      crypto: require.resolve("crypto-browserify"),
      path: require.resolve("path-browserify"),
      fs: false,
    };
    config.plugins = config.plugins || [];
    config.plugins.push(new NodePolyfillPlugin());
    return config;
  },
};

Install optional polyfill packages

npm
yarn
pnpm
bun
npm install -D node-polyfill-webpack-plugin crypto-browserify path-browserify

Extension APIs vs Node APIs

polyfill: true in CLI/config is for webextension-polyfill (browser.* API ergonomics), not Node core module polyfills.

Use Node polyfills only for libraries that cannot run with standard Web APIs.

Caveats

  • Do not assume filesystem access in extension runtime; keep fs: false unless you have a very specific browser-safe strategy.
  • Prefer Web Crypto (crypto.subtle) over large Node crypto shims when possible.
  • Polyfills increase bundle size and can affect startup time in extension pages/content scripts.
  • Some packages using node: specifiers may need explicit fallback handling.

Next steps

Video walkthrough

Video demo soon: node polyfill setup workflow