build compiles your extension in production mode and writes output to dist/<browser>.
For monorepo/submodule projects, see Environment variables for configuration-time env resolution (project root first, then workspace-root fallback).
When to use build
- Preparing extension packages for Chrome Web Store, Edge Add-ons, or Firefox Add-ons.
- Running continuous integration (CI) jobs that produce repeatable production artifacts.
- Validating production bundle output and browser-target differences before submission.
Build command capabilities
Usage
Build output
After runningbuild, Extension.js generates optimized files for the selected browser targets. Output goes to dist/ with one subfolder per target. Each folder contains bundled JavaScript, CSS, HTML, and required runtime assets.
For TypeScript projects,
build also regenerates the extension-env.d.ts
ambient type declarations (the same file dev writes),
so a CI tsc --noEmit stays clean whether or not you ran dev first.
JavaScript-only projects skip this step.Browser target matrix
What engine targets mean for build
build never launches a browser, so engine targets don’t point at a binary here, but they still produce a distinct artifact, not a renamed copy of a named-target build:
- Own output folder.
--browser=chromium-basedwrites todist/chromium-based, the same folderdev,preview, andstartuse for that target, so a project developed against a custom Chromium binary builds to matching paths. - Own env resolution.
.env.chromium-basedand.env.chromium-based.productionwin over the family’s.env.chromium/.env.chrome/.env.edge, and bundled code seesEXTENSION_BROWSER === "chromium-based", so code and config can branch on “generic Chromium” vs a specific store build. - Own manifest prefix.
chromium-based:keys inmanifest.jsonresolve as the most-specific match for this target, on top of the family-widechrome:/chromium:/edge:keys.
gecko-based works the same way relative to firefox. No browser binary is required, and --chromium-binary/--gecko-binary only matter for commands that launch a browser.
Arguments and flags
--author and --author-mode are hidden, deprecated aliases for --debug.
Safari flags
These flags apply tosafari and webkit-based targets only. Passing any of them with another target exits with an error, so a typo never no-ops silently.
Safari packaging runs a preflight before the build. On a non-macOS host,
build warns and skips the Safari packaging step but still compiles the bundle. On macOS with a broken or missing Xcode, the failure is fatal.
Shared global options
Also supports Global flags.Mode override
--mode overrides the bundler mode and NODE_ENV for the build. Accepts development, production, or none. Use it to mirror Vite/webpack workflows where you need a non-production bundle for staging or debugging.
production.
Zip behavior
Each zip lands inside its own
dist/<browser> folder, next to the unpacked output. Without --zip-filename, the name is the manifest name lowercased with every character outside a-z0-9 and spaces removed, remaining spaces turned into dashes, then the manifest version. A manifest named My Extension+ at version 1.0.0 packages as dist/chrome/my-extension-1.0.0.zip. Because the name is rewritten, read the emitted path from the build output instead of composing it from the manifest name.
Examples
Building with zip output and custom filename
my-extension.zip.
Building with polyfill support
Building source and artifact zip
What a successful build prints
After the asset summary, a successful build prints the output directory and its size, then a link you can use to share the build for review:compiled with warnings instead of compiled in.
Do not gate CI on this prose. It is written for people and it changes between
releases. Use the exit code, or --output json below, which is the supported
machine contract.
Machine output with --output json
--output json prints one schema-1 envelope on stdout and routes the human build lines to stderr. Stdout stays parseable as a single JSON document.
- A successful run prints a
status: "built"frame. Itsvaluecarries the built browsers, the resolved mode, and one summary per browser. Each summary records the output path, asset totals, warning text, and the Safari app identity when relevant. - A failed build prints one
ok: falseframe withstatus: "build-failed"anderror.code: "E_COMPILE"before the process exits1.
dist/extension-js/<browser>/build-summary.json. Scripts that shell out to extension build can read structured warnings there. Guard against stale files by checking the file’s modification time.
Best practices
- Check build logs: Review logs for warnings and missing assets after each build.
- Optimize your manifest: Keep
manifest.jsoncompatible with every target browser. - Name artifacts intentionally: Use
--zip-filenamefor stable CI artifact naming. - Validate target output: Check each
dist/<browser>folder before publishing. A laterdevsession overwrites that same folder with a dev-instrumented build that adds permissions such asscripting,tabs,management, andstorage, plushost_permissionsfor<all_urls>and broad web-accessible resources. Runbuildagain before you package or publish.
Next steps
- Send the build to a reviewer behind a link by following Share an unpublished build for review.
- Submit the artifacts to the browser stores by following the extension.dev publish docs.
- Get a shareable URL for a project on extension.dev with
publish. - Run existing build output with
preview. - Build and launch in one command with
start. - Configure shared defaults in
extension.config.js. - Review configuration env loading behavior in Environment variables.
- Review supported targets in Browsers available.

