Extension config (extension.config.js)

Use one config file to set browser defaults, command behavior, and bundler customization.

Share browser defaults, command options, and build settings across your team without repeating CLI flags. Extension.js reads extension.config.js (or .mjs / .cjs) from your project root and applies it to dev, start, preview, build, and bundler config.

How it works

Add extension.config.js at your project root (same level as package.json in typical setups).

Supported file names:

  • extension.config.js
  • extension.config.mjs
  • extension.config.cjs

Top-level keys:

Key Description
browser Browser-specific defaults keyed by browser target.
commands Per-command defaults (dev, start, preview, build).
extensions Companion extensions applied across commands (load-only).
transpilePackages Default package transpile allowlist (monorepo/workspace support).
config Hook to extend/override generated webpack/rspack config.

Video demo soon: extension config basics

Browser configuration

Need different browser defaults per target? Use browser:

export default {
  browser: {
    chrome: {
      profile: "path/to/profile",
      preferences: { darkMode: true },
      browserFlags: ["--disable-web-security"],
      excludeBrowserFlags: ["--mute-audio"],
    },
    "chromium-based": {
      chromiumBinary: "/path/to/brave-or-other-chromium-binary",
    },
    firefox: {
      geckoBinary: "/path/to/firefox",
    },
  },
};

Supported browser keys include: chrome, edge, firefox, chromium, chromium-based, gecko-based.

Common browser fields:

  • profile, persistProfile
  • preferences
  • browserFlags, excludeBrowserFlags
  • chromiumBinary, geckoBinary
  • extensions (companion load-only extensions)

Browser target capabilities

Key What it does
profile Sets the browser profile path (or profile behavior) used when launching.
persistProfile Reuses profile data between runs.
preferences Applies browser preference overrides.
browserFlags Adds launch flags for the browser process.
excludeBrowserFlags Removes default launch flags you do not want.
chromiumBinary Uses a custom Chromium-family binary path.
geckoBinary Uses a custom Gecko/Firefox binary path.
extensions Loads companion extensions together with the main extension.

Video demo soon: browser defaults by target

Commands configuration

Use commands to define defaults per command:

export default {
  transpilePackages: ["@workspace/ui"],
  commands: {
    dev: {
      browser: "chrome",
      polyfill: true,
      logLevel: "info",
      persistProfile: true,
      browserFlags: ["--headless=new"],
      extensions: { dir: "./extensions" },
    },
    start: {
      browser: "firefox",
      source: "https://example.com",
    },
    preview: {
      browser: "edge",
      noRunner: false,
    },
    build: {
      browser: "chrome",
      zip: true,
      zipSource: true,
      zipFilename: "my-extension.zip",
      transpilePackages: ["@workspace/ui", "@workspace/icons"],
    },
  },
};

Notes:

  • Top-level extensions and transpilePackages are merged into command defaults.
  • Per-command values override top-level values.
  • start is supported the same way as dev/preview/build.

Command capabilities (shared)

Key Applies to What it does
browser dev, start, preview, build Sets browser or browser-family target.
profile dev, start, preview Sets browser profile path/behavior.
persistProfile dev, start, preview Reuses browser profile data between runs.
chromiumBinary dev, start, preview Uses a custom Chromium-family binary.
geckoBinary dev, start, preview Uses a custom Gecko-family binary.
polyfill dev, start, build Enables compatibility polyfill behavior where relevant.
startingUrl dev, start, preview Opens a specific URL on browser launch.
port dev, start, preview Sets runner/devtools port.
noRunner dev, start, preview Disables browser runner launch.
extensions dev, start, preview, build Loads companion extensions (or extension list).
install dev, start, build Installs missing dependencies before running.
transpilePackages dev, start, preview, build Transpiles listed workspace/external packages.

build command capabilities

Key What it does
zip Generates a packaged zip artifact.
zipSource Adds source bundle/archive output for review/compliance workflows.
zipFilename Sets a custom zip output filename.
silent Reduces build log output.

dev command capabilities

Key What it does
noOpen Runs dev server without auto-opening browser.
source Enables source-inspection flow from a remote source URL.
watchSource Re-runs source inspection when watched updates occur.
sourceFormat Sets source output format (pretty, json, ndjson).
sourceSummary Emits compact source summary output.
sourceMeta Includes page metadata in source output.
sourceProbe Probes source output with specific CSS selectors.
sourceTree Controls compact extension tree output.
sourceConsole Includes console summary in source output.
sourceDom Includes DOM snapshots/diffs in source output.
sourceMaxBytes Caps source output payload size.
sourceRedact Controls source redaction strategy.
sourceIncludeShadow Controls Shadow DOM inclusion strategy.
sourceDiff Includes diff metadata on source watch updates.

Logging capabilities

Key Applies to What it does
logs dev, start, preview Sets minimum log level (off to all).
logContext dev, start, preview Filters logs by context (background, content, etc.).
logFormat dev, start, preview Sets output format (pretty, json, ndjson).
logUrl dev, start, preview Filters logs by URL pattern.
logTab dev, start, preview Filters logs by tab ID.

Video demo soon: command-level defaults

Webpack configuration

Need advanced bundler customization? Use config to patch the generated config:

export default {
  config: (config) => {
    config.module.rules.push({
      test: /\.mdx$/,
      use: ["babel-loader", "@mdx-js/loader"],
    });
    return config;
  },
};

config may also be an object, which is merged on top of the generated config.

Video demo soon: bundler config override

Full sample

export default {
  browser: {
    chrome: { browser: "chrome", profile: "default" },
    firefox: { browser: "firefox", persistProfile: true },
    "chromium-based": {
      browser: "chromium-based",
      chromiumBinary:
        "/Applications/Brave Browser.app/Contents/MacOS/Brave Browser",
    },
  },
  commands: {
    dev: {
      browser: "chrome",
      polyfill: true,
      extensions: { dir: "./extensions" },
    },
    start: { browser: "edge" },
    preview: { browser: "firefox" },
    build: {
      zipFilename: "extension.zip",
      zip: true,
      zipSource: true,
    },
  },
  extensions: { dir: "./extensions" },
  transpilePackages: ["@workspace/ui"],
  config: (config) => config,
};

Best practices

  • Keep browser-specific values in browser: Keep command definitions focused on workflow, not browser internals.
  • Use top-level defaults intentionally: Put shared extensions / transpilePackages at root; override only where needed.
  • Prefer chromiumBinary/geckoBinary names: They align with current command and type surface.
  • Keep config hook minimal: Add only what cannot be expressed through first-class Extension.js options.

Next steps