import/export syntax across all extension contexts.
Extension.js supports ECMAScript Modules (ESM) in background scripts, content scripts, and extension pages. It uses the default Rspack pipeline for module resolution.
When ESM is a good fit
- You want consistent module syntax across extension and web code.
- You are sharing code with modern ESM-first packages.
- You need cleaner tree-shaking (automatic removal of unused code) and explicit dependency boundaries.
Template examples
new

content

Usage with an existing extension
You can use ESM syntax directly in extension source files (.js, .mjs, .ts, .tsx, etc.) without custom bundler setup.
If your Node.js project configuration files should also run as ESM, set "type": "module" in package.json. This applies to custom scripts and configuration conventions:
Manifest and service worker notes
For Manifest V3 background workers:- Set
background.typeto"module"when you want native ES module loading in the service worker. - Without module worker type, Extension.js uses classic worker loading (bundled scripts without native module syntax).
ESM vs CommonJS reminders
When writing ESM modules:Include file extensions in relative imports
Interoperability with non-ESM modules can differ
When importing CommonJS packages from ESM, follow the compatibility guidance each package provides.CommonJS globals are not available in strict ESM contexts
Avoid relying onrequire, module.exports, __filename, and __dirname inside ESM modules.
Handling environment variables in ECMAScript modules
Extension.js supports both:process.env.EXTENSION_PUBLIC_*import.meta.env.EXTENSION_PUBLIC_*
EXTENSION_PUBLIC_ for variables you want available in extension code.
Do imports need mandatory file extensions?
Node.js requires explicit file extensions in ESM import specifiers (import "./util.js", never import "./util"). That rule applies to code Node runs directly, and it confuses people coming to extensions from server code.
In Extension.js the bundler resolves imports, not Node, so both styles work in extension code:
- Scripts your
package.jsonruns with Node directly (build helpers, codegen): extensions are mandatory there. .mjsfiles shared between Node tooling and extension code: write extensions so both resolvers accept them.
Next steps
- Learn more about TypeScript.
- Explore how Extension.js handles CSS modules.

