CLI commands
ExtForge’s CLI is invoked as extforge <command>. All commands read extforge.config.ts from the current working directory unless otherwise noted.
Create a new browser extension project from an interactive scaffold.
Synopsis
Section titled “Synopsis”extforge init [name] [--defaults] [--dir <path>]Arguments and flags
Section titled “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
Section titled “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
Section titled “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 devStart the development server with file watching and HMR.
Synopsis
Section titled “Synopsis”extforge dev [--browser <name>] [--port <n>] [--host <host>] [--quiet] [--verbose] [--json] [--once]| 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
Section titled “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 the extension for production.
Synopsis
Section titled “Synopsis”extforge build [--browser <name>] [--dev] [--sourcemap] [--strict] [--quiet] [--json]| 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
Section titled “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
Section titled “Example output”✔ chrome: 3 entries bundled in 412ms → dist/chrome/✔ firefox: 3 entries bundled in 398ms → dist/firefox/validate
Section titled “validate”Validate project structure and config without building.
Synopsis
Section titled “Synopsis”extforge validate [--quiet] [--json]| Flag | Default | Description |
|---|---|---|
--quiet | false | Suppress info-level output. |
--json | false | Emit newline-delimited JSON log lines. |
What it does
Section titled “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
Section titled “Example output”✔ Config valid✔ Manifest: name, version, permissions OK⚠ Manifest: sidePanel declared but sidePanel permission not in required[]✔ All checks passeddoctor
Section titled “doctor”Diagnose the project and environment, checking for common problems.
Synopsis
Section titled “Synopsis”extforge doctor [--json] [--quiet]| Flag | Default | Description |
|---|---|---|
--json | false | Emit the full report as a JSON object to stdout. |
--quiet | false | Suppress info-level output. |
What it does
Section titled “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)
Section titled “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)
Section titled “Example 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
Section titled “package”Create .zip archives of built extensions for store submission.
Synopsis
Section titled “Synopsis”extforge package [--browser <name>]| Flag | Description |
|---|---|
--browser | Package a single browser only. |
What it does
Section titled “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 is sanitised: anything outside [a-zA-Z0-9._-] in manifest.name/manifest.version is replaced with _ so no path component can be misinterpreted as a shell argument.
Cross-platform
Section titled “Cross-platform”extforge package prefers the system zip binary (faster, more battle-tested) and falls back to a pure-Node ZIP writer when zip isn’t installed — typical on Windows. The fallback produces deterministic, byte-for-byte reproducible archives (fixed DOS timestamp, sorted entries, DEFLATE via node:zlib) and skips .DS_Store / .git automatically. No additional dependencies.
Example output
Section titled “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` firstGenerate PNG icons from an SVG source.
Synopsis
Section titled “Synopsis”extforge iconsWhat it does
Section titled “What 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
Section titled “upgrade”Check whether your config uses any deprecated fields.
Synopsis
Section titled “Synopsis”extforge upgradeWhat it does
Section titled “What 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
Section titled “Example output”✔ Your extforge.config is up to date.Or, on failure:
✖ Config is invalid; fix it before running upgrade.