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.

Video demo soon: env file priority resolution

Built-in environment variables

Extension.js injects built-in variables at compile time, so browser and mode are always available in your extension code.

Variable Name Description
EXTENSION_PUBLIC_BROWSER The current browser target for your extension (e.g., chrome, firefox, edge).
EXTENSION_PUBLIC_MODE The mode in which your extension is running, such as development or production.
EXTENSION_BROWSER Browser target (non-legacy alias).
EXTENSION_MODE Build mode (non-legacy alias).
BROWSER Short browser alias.
MODE Short mode alias.
NODE_ENV Node environment aligned to compiler mode (development / production).

All built-ins above are available through both process.env.* and import.meta.env.*.

Environment variable inventory

Public/runtime variables (user-defined)

Variable pattern Purpose Available in JS runtime Notes
EXTENSION_PUBLIC_* Expose user-defined values to extension code Yes (process.env + import.meta.env) Safe-to-ship values only

Static placeholder variables

Variable pattern Purpose Available in JS runtime Notes
$EXTENSION_* tokens in emitted .html / .json Build-time placeholder replacement in static assets Not as JS vars Avoid using secrets in static templates

Built-in/alias variables

Variable Type Notes
EXTENSION_PUBLIC_BROWSER built-in Browser target
EXTENSION_PUBLIC_MODE built-in Build mode
EXTENSION_BROWSER built-in alias Browser target
EXTENSION_MODE built-in alias Build mode
BROWSER built-in alias Short browser name
MODE built-in alias Short mode name
NODE_ENV built-in Compiler mode

CLI and dev-server operational variables

Variable Purpose Typical usage
EXTENSION_AUTO_EXIT_MS Auto-exit dev process after N ms CI hard-stop control
EXTENSION_FORCE_KILL_MS Force-kill timeout fallback CI cleanup resilience
EXTENSION_VERBOSE Verbose diagnostics in selected flows Debugging CLI behavior
EXTENSION_AUTHOR_MODE Maintainer/author diagnostics mode Internal diagnostics and tooling

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:

# .env.chrome.development
EXTENSION_PUBLIC_API_URL=https://api-dev.chrome.com
# .env.firefox.production
EXTENSION_PUBLIC_API_URL=https://api.firefox.com

Video demo soon: browser-specific env variants

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).

# .env
EXTENSION_PUBLIC_API_KEY=your_api_key_here
EXTENSION_PUBLIC_SITE_URL=https://example.com
PRIVATE_KEY=abc123  # Not injected into JS bundles

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:

{
  "name": "My Extension",
  "version": "1.0",
  "description": "This extension is connected to $EXTENSION_PUBLIC_API_KEY",
  "background": {
    "service_worker": "service_worker.js"
  }
}

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:

{
  "appName": {
    "message": "My Extension - $EXTENSION_PUBLIC_SITE_URL"
  },
  "appDescription": {
    "message": "Connected to API at $EXTENSION_PUBLIC_API_KEY"
  }
}

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/):

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>My Extension</title>
  </head>
  <body>
    <h1>Welcome to My Extension</h1>
    <p>API Key: $EXTENSION_PUBLIC_API_KEY</p>
  </body>
</html>

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:

const ApiInfo = () => {
  const apiUrl = process.env.EXTENSION_PUBLIC_SITE_URL;
  const apiKey = process.env.EXTENSION_PUBLIC_API_KEY;

  return (
    <div>
      <h1>API Information</h1>
      <p>URL: {apiUrl}</p>
      <p>Key: {apiKey}</p>
    </div>
  );
};

export default ApiInfo;

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:

service_worker.mjs;
const apiUrl = import.meta.env.EXTENSION_PUBLIC_API_URL;
console.log(`API URL for the current environment: ${apiUrl}`);

import.meta.env and process.env have parity for injected env keys.

Video demo soon: using env values across extension files

Best practices

  • Expose only what must ship: Prefix only client-safe keys with EXTENSION_PUBLIC_.
  • Use .env.defaults for 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.example and ignore real env files (.env, .env.local, browser/mode variants).

Next steps