CLI commands
ExtForge’s CLI is invoked as extforge <command>. All commands read extforge.config.ts from the current working directory unless otherwise noted.
init
Create a new browser extension project from an interactive scaffold.
Synopsis
extforge init [name] [--defaults] [--dir <path>]Arguments and flags
| Argument / Flag | Type | Description |
|---|---|---|
name | positional (optional) | Project name. Prompted if not supplied. |
--defaults | boolean | Skip all prompts and use defaults (react, tailwind, chrome firefox, popup background). |
--dir | string | Target directory. Defaults to a subdirectory named after the project. |
What it does
Runs the interactive scaffold:
- Prompts for project name, framework (
react,vue,svelte,solid,vanilla), CSS (tailwind,vanilla,none), browsers, and features (popup,background,content,options,sidepanel). - Creates the directory structure,
extforge.config.ts,package.json,tsconfig.json, and source templates. - Writes
.gitignore,vitest.config.ts, and E2E fixtures.
Example output
✔ Project name: my-extension✔ Framework: react✔ CSS: tailwind✔ Browsers: chrome, firefox✔ Features: popup, background
Scaffolding my-extension...✔ Created my-extension/extforge.config.ts✔ Created my-extension/src/ui/popup/popup.tsx✔ Created my-extension/src/background/index.ts✔ Done. cd my-extension && pnpm install && extforge devdev
Start the development server with file watching and HMR.
Synopsis
extforge dev [--browser <name>] [--port <n>] [--host <host>] [--quiet] [--verbose] [--json] [--once]Flags
| Flag | Default | Description |
|---|---|---|
--browser | chrome | Browser target for the dev build. |
--port | 35729 | HMR WebSocket port. |
--host | localhost | HMR host. |
--quiet | false | Suppress info-level output. |
--verbose | false | Log every file change and reload decision. |
--json | false | Emit newline-delimited JSON log lines. |
--once | false | Run a single dev build then exit (useful in CI). |
What it does
- Validates the project structure.
- Builds the extension in dev mode (source maps on, HMR client injected).
- Starts a WebSocket server on
--port. - Watches the
src/directory for changes and applies the appropriate reload strategy per change type.
Exits 0 on clean shutdown (SIGINT / SIGTERM). Exits 1 if --once is passed and the build has errors.
See the HMR guide for reload strategies and troubleshooting.
build
Build the extension for production.
Synopsis
extforge build [--browser <name>] [--dev] [--sourcemap] [--strict] [--quiet] [--json]Flags
| Flag | Default | Description |
|---|---|---|
--browser | (all from config) | Build a single browser instead of all. |
--dev | false | Development build (source maps on, HMR client injected). |
--sourcemap | false | Include source maps (implied by --dev). |
--strict | false | Treat cross-browser compat warnings as errors. |
--quiet | false | Suppress info-level output. |
--json | false | Emit newline-delimited JSON log lines. |
What it does
Iterates config.browsers (or the single --browser target), runs esbuild on each entry point, generates manifest.json for each browser, and writes output to dist/<browser>/.
Exits 0 on success, 1 if any browser’s build has errors.
Example output
✔ chrome: 3 entries bundled in 412ms → dist/chrome/✔ firefox: 3 entries bundled in 398ms → dist/firefox/validate
Validate project structure and config without building.
Synopsis
extforge validate [--quiet] [--json]Flags
| Flag | Default | Description |
|---|---|---|
--quiet | false | Suppress info-level output. |
--json | false | Emit newline-delimited JSON log lines. |
What it does
- Checks that
extforge.config.tsexists and passes the Zod schema. - Validates the
manifestconfig for required fields and known permission names. - Checks that declared entry-point files exist.
Exits 0 if all checks pass, 1 if any error is found. Warnings print but do not affect the exit code.
Example output
✔ Config valid✔ Manifest: name, version, permissions OK⚠ Manifest: sidePanel declared but sidePanel permission not in required[]✔ All checks passeddoctor
Diagnose the project and environment, checking for common problems.
Synopsis
extforge doctor [--json] [--quiet]Flags
| Flag | Default | Description |
|---|---|---|
--json | false | Emit the full report as a JSON object to stdout. |
--quiet | false | Suppress info-level output. |
What it does
Runs a fixed set of checks:
| Check | What it tests |
|---|---|
node-version | Node.js meets the minimum version requirement |
config-valid | Config file loads and validates without error |
icons-present | PNG icons exist at expected sizes (16, 32, 48, 128) |
port-free | HMR port (dev.port) is not already bound |
dist-gitignored | dist/ is listed in .gitignore |
permissions-known | All declared permissions are in the known MV3 permission list |
browser-overrides | Browser override keys are valid browser names |
scripts-present | Declared entry-point files exist on disk |
compat | No cross-browser compat issues (warn-only by default) |
Each check has a status: pass, warn, fail, or info. doctor exits 0 if no check fails, 1 if any check has fail status.
Example output (human)
✔ node-version: Node 22.4.0 meets requirement✔ config-valid: Config loaded successfully✖ icons-present: icons/icon-48.png missing hint: Run `extforge icons` to generate from icons/icon.svg⚠ compat: chrome.tabGroups.query not supported on safari (src/background/index.ts:12)
Summary pass: 7 warn: 1 fail: 1Example output (--json)
{ "v": 1, "summary": { "pass": 7, "warn": 1, "fail": 1 }, "exitCode": 1, "results": [ { "name": "icons-present", "status": "fail", "message": "icons/icon-48.png missing", "hint": "Run `extforge icons`" } ]}package
Create .zip archives of built extensions for store submission.
Synopsis
extforge package [--browser <name>]Flags
| Flag | Description |
|---|---|
--browser | Package a single browser only. |
What it does
For each browser in config.browsers (or the single --browser target):
- Checks that
dist/<browser>/exists. Skips with a warning if not. - Creates
packages/<name>-<browser>-v<version>.zipfrom all files in the dist directory.
The filename components come from manifest.name and manifest.version.
Example output
✔ Packaged chrome → packages/My Extension-chrome-v1.0.0.zip✔ Packaged firefox → packages/My Extension-firefox-v1.0.0.zip⚠ No build for safari — run `extforge build` firsticons
Generate PNG icons from an SVG source.
Synopsis
extforge iconsWhat it does
Reads icons/icon.svg and generates icons/icon-16.png, icon-32.png, icon-48.png, and icon-128.png.
Tries sharp-cli first (npx sharp-cli). Falls back to cairosvg (Python). If neither is available, prints an install hint and exits 1.
✔ Generated icon-16.png✔ Generated icon-32.png✔ Generated icon-48.png✔ Generated icon-128.pngupgrade
Check whether your config uses any deprecated fields.
Synopsis
extforge upgradeWhat it does
Loads extforge.config.ts through the current schema. If the load succeeds, reports that the config is up to date. If the load fails (e.g. an old field is no longer valid), reports the error so you can fix it manually.
Example output
✔ Your extforge.config is up to date.Or, on failure:
✖ Config is invalid; fix it before running upgrade.