Environment variables
Use one extension codebase across browsers and environments without hardcoding values.
Manage API hosts, keys, and browser-specific values cleanly across environments. Extension.js resolves env files during compilation, injects public variables into JavaScript (process.env and import.meta.env), and replaces placeholders in emitted .json and .html assets.
How it works
Extension.js checks environment files in priority order and uses the first matching file:
.env.[browser].[mode]: Browser-specific environment variables for a specific mode..env.[browser]: Browser-specific environment variables..env.[mode]: Mode-specific environment variables..env.local: Local-only overrides..env: Default environment variables..env.example: Fallback when no env file above exists.
In addition, .env.defaults is loaded as default values, and system environment variables (process.env) take final precedence.
Note: File selection is single-file priority (plus
.env.defaults+ system env), not full cascading across all files.
extension.config.* env resolution in monorepos
When loading extension.config.js / .mjs / .cjs, Extension.js preloads env files into process.env:
- It first resolves from the extension project directory.
- If no
.env*file exists there, it falls back to the nearest workspace root (directory containingpnpm-workspace.yaml) and applies the same priority order.
This makes submodule-style extension apps work with shared monorepo root env files without custom dotenv setup.
Built-in environment variables
Extension.js injects built-in variables at compile time, so browser and mode are always available in your extension code.
All built-ins above are available through both process.env.* and import.meta.env.*.
Environment variable inventory
Public/runtime variables (user-defined)
Static placeholder variables
Built-in/alias variables
CLI and dev-server operational variables
Browser-specific environment files
Need different values per browser? Extension.js supports browser-scoped env files such as .env.chrome and .env.firefox. You can also combine browser and mode for a single build variant:
.env.chrome.development: Applied only when running the extension in Chrome during development mode..env.firefox.production: Applied only when building the extension for Firefox in production mode.
Priority order is:
.env.[browser].[mode].env.[browser].env.[mode].env.local.env.env.example
Example files:
Custom environment variables
You can define custom variables in env files at project root.
Only variables prefixed with EXTENSION_PUBLIC_ are injected into JavaScript bundles (process.env / import.meta.env).
Important: Variables without EXTENSION_PUBLIC_ are not injected into JS bundles.
However, placeholders in emitted .json/.html files can resolve $EXTENSION_* tokens, so avoid referencing secrets in static asset templates.
Using environment variables
You can use environment variables in manifest.json, locales, HTML, and JavaScript/TypeScript files.
1. In manifest.json
manifest.json does not natively support environment variables, but Extension.js replaces supported placeholders during build. For example:
During compilation, $EXTENSION_PUBLIC_API_KEY is replaced with the resolved env value.
2. In locale files
You can also use placeholders in locale files when values should change by environment. For example:
When assets are emitted, placeholders such as $EXTENSION_PUBLIC_SITE_URL are replaced with resolved values.
3. In HTML files
You can also use placeholders in static HTML files (for example, under pages/):
When built, $EXTENSION_PUBLIC_API_KEY is replaced in the output HTML.
4. In JSX components
In React/JSX/TS files, read env values with process.env:
These values are inlined at compile time and can vary by browser/mode.
import.meta support
For ESM workflows, Extension.js also supports import.meta.env:
import.meta.env and process.env have parity for injected env keys.
Best practices
- Expose only what must ship: Prefix only client-safe keys with
EXTENSION_PUBLIC_. - Use
.env.defaultsfor shared defaults: Keep predictable team defaults while allowing local/system overrides. - Keep secrets out of static placeholders: Avoid putting secret
$EXTENSION_*tokens in HTML/JSON templates. - Version control hygiene: Commit
.env.exampleand ignore real env files (.env,.env.local, browser/mode variants).
Next steps
- Review browser targeting in browsers available.
- Configure shared defaults in
extension.config.js.
