> ## Documentation Index
> Fetch the complete documentation index at: https://extension.js.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Start command for build-and-launch workflow

> Run a production build and immediately launch the extension in the browser with one command. Combines build and preview into a single step.

Use `start` when you want a production build and immediate browser launch in one command.

The `start` command runs a production build first, then launches the built extension using the same flow as the `preview` command.

## When to use `start`

* Manually validating production behavior right after compilation.
* Reproducing runtime differences between watch mode and production output.
* Running a production-like check locally without a separate `build` then `preview` step.

## Start command capabilities

| Capability | What it gives you |
| - | - |
| Build + launch workflow | Run production compile and browser launch in one step |
| Target selection | Start directly in selected browser or engine target |
| Runner control | Skip browser launch when you only need build verification |
| Production-like validation | Check real compiled output instead of watch-mode state |

## How it differs from other commands

* `dev`: dev server + hot module replacement (HMR)/watch mode
* `build`: production build only
* `preview`: launch an existing built extension without building
* `start`: `build` + `preview` in sequence

## Usage

<CodeGroup>
  ```bash npm theme={null}
  extension start [path-or-url] [options]
  ```

  ```bash pnpm theme={null}
  extension start [path-or-url] [options]
  ```

  ```bash yarn theme={null}
  extension start [path-or-url] [options]
  ```

  ```bash bun theme={null}
  extension start [path-or-url] [options]
  ```

  ```bash deno theme={null}
  extension start [path-or-url] [options]
  ```
</CodeGroup>

If you omit the path, the command uses the current working folder.

## Arguments and flags

| Flag | Alias | What it does | Default |
| - | - | - | - |
| `[path or url]` | - | Extension path or remote URL. | `process.cwd()` |
| `--browser <browser>` | - | Browser/engine target. | `commands.start.browser`, else `chromium` |
| `--profile <path\|boolean>` | - | Browser profile path or boolean profile mode. | fresh profile |
| `--chromium-binary <path>` | - | Custom Chromium-family binary path. | system default |
| `--gecko-binary <path>` | `--firefox-binary` | Custom Gecko-family binary path. | system default |
| `--polyfill [boolean]` | - | Enable `browser.*` API compatibility polyfill for Chromium targets. | `true` |
| `--no-polyfill` | - | Disable the cross-browser polyfill. | polyfill enabled |
| `--starting-url <url>` | - | Starting URL in launched browser. | unset |
| `--no-open` | - | Launch the browser, but do not open a tab for your extension. The browser still starts and loads it. See [stop the browser from launching](#stop-the-browser-from-launching). | a tab opens on launch |
| `--no-browser` | - | Stop the browser from launching. The build still runs. See [stop the browser from launching](#stop-the-browser-from-launching). | browser launch enabled |
| `--wait [boolean]` | - | Wait for `dist/extension-js/<browser>/ready.json` and exit. | disabled |
| `--wait-timeout <ms>` | - | Timeout for `--wait` mode. | `60000` |
| `--output <pretty\|json>` | - | Result format. `json` prints a schema-1 envelope on stdout. | `pretty` |
| `--port <port>` | - | Runner/devtools port when runner is enabled. Use `0` for OS-assigned port. | `8080` |
| `--host <host>` | - | Host to bind the dev server to. Use `0.0.0.0` for Docker/dev containers. | `127.0.0.1` |
| `--public-host <host>` | - | Accepted for parity with `dev`, so a script that shares flags between the two is not refused. `start` serves nothing, so the value has no effect. | unset |
| `--extensions <list>` | - | Comma-separated companion extensions or store URLs. | unset |
| `--install [boolean]` | - | Internal flag. Install project dependencies when missing. | command behavior default |
| `--debug` | - | Enable maintainer diagnostics. | disabled |

Two deprecated aliases are hidden from `--help` but still work:

* `--wait-format <pretty|json>` maps onto `--output` and warns once on stderr. Migrate scripts to `--output`.
* `--author` and `--author-mode` map onto `--debug`.

## Browser support

`start` has no Safari path. Passing `--browser safari` (or `webkit-based`) exits with `E_COMMAND_UNSUPPORTED_FOR_TARGET`. The reason is measured. Safari's WebDriver route does load an unpacked folder, and the background even runs, but Safari grants the extension zero host origins. Content scripts never inject, and no API call can grant the access afterwards. Use [`dev`](/docs/commands/dev) or [`build`](/docs/commands/build) for Safari targets.

## Automation metadata

`start` writes readiness metadata to:

* `dist/extension-js/<browser>/ready.json`

This is useful for automation when using `--no-browser`:

* Wait for `status: "ready"` before launching external runners.
* Handle `status: "error"` as a deterministic failure signal.
* Use `runId` and `startedAt` to correlate a specific runtime session.

### Stop the browser from launching

Two flags sound alike and do different things:

| You want | Flag | What happens |
| - | - | - |
| No browser at all | `--no-browser` | No browser process starts. The production build still runs. |
| A browser, but no tab opened for your extension | `--no-open` | The browser starts and loads your extension. No tab is opened for it. |

```bash theme={null}
# Stop the browser launch. The production build still runs.
extension start --no-browser

# Launch the browser without opening a tab for the extension.
extension start --no-open
```

`--no-browser` also has a config form, `commands.start.noBrowser: true`, and an environment form, `EXTENSION_CLI_NO_BROWSER=1`. `dev`, `start`, and `preview` all accept both flags.

### `--no-browser` and readiness synchronization

`--no-browser` only disables browser launch. It does not block external runners until the production build finishes.

For production-oriented Playwright, continuous integration (CI), and AI workflows:

1. Run `extension start --no-browser` as the producer process.
2. Run `extension start --wait --browser=<browser>` as the readiness gate.
3. Launch external browser automation only after `status: "ready"`.

`--wait` exits non-zero on `error`/timeout and ignores stale contracts from dead processes (`pid` no longer alive).
Because `start` can finish quickly, a contract from a completed run still counts when its timestamp is within a 60 second window.
`--wait` requires a local project path. Passing a remote URL exits with `E_ARGS`.
Passing both `--wait` and `--no-browser` in the same invocation exits with `E_INVALID_OPTION`, because `--wait` only reads a contract that another process writes. Run them as two processes, as in the steps above.

### Machine output with `--output json`

`--output json` prints schema-1 envelopes on stdout, one JSON object per line:

* A plain `start` run prints one `status: "started"` frame once the build finished and the browser launched. It carries the project path, browser list, `pid`, and `port: null`, because a run-only session binds no port. A run that fails prints only its failure frame, never a `started` frame before it.
* A `start --wait` run prints one `status: "ready"` frame on success. Its `value.results` array carries the full ready contract per browser.
* A `start --wait` run that reads a contract in `error` status prints one `ok: false` frame that names the cause, for example `E_BROWSER_LAUNCH` when the browser never started or `E_BROWSER_EXITED` when it exited. See [the ready.json contract](/docs/contracts/ready-json) for the full list.
* A failed build prints one `ok: false` frame with `status: "build-failed"` before the process exits `1`. A compile error carries `error.code: "E_COMPILE"`. A missing project folder carries `E_PROJECT_NOT_FOUND`, a folder with no manifest carries `E_MANIFEST_NOT_FOUND`, and a manifest that does not parse carries `E_MANIFEST_INVALID`. A config file that fails to load carries `E_CONFIG_LOAD`, and a remote URL that gives no usable archive carries `E_REMOTE_ZIP_INVALID`, `E_REMOTE_FETCH_TIMEOUT`, or `E_REMOTE_DOWNLOAD`.
* A bad `--chromium-binary` or `--gecko-binary` pin prints one `ok: false` frame with `status: "usage"` and `error.code: "E_BROWSER_BINARY_INVALID"`. That covers a path that does not exist, a file that is not executable, and a binary that does not answer its version probe within 10 seconds. The command ends and leaves nothing running.
* A browser that cannot start prints one `ok: false` frame with `status: "failed"`. The code is `E_BROWSER_LAUNCH` when the binary is executable but the system cannot start it or Firefox exits before its debugger answers, and `E_BROWSER_CONNECT` when Firefox runs but its debugger never answers.

## Logging flags

These flags are experimental and may change between minor releases.

| Flag | What it does | Default |
| - | - | - |
| `--logs <off\|error\|warn\|info\|debug\|trace\|all>` | Minimum log level. | `off` |
| `--log-context <list\|all>` | Context filter (`background`, `content`, `page`, `popup`, `options`, `sidebar`, `devtools`, `newtab`, `history`, `bookmarks`). | `all` |
| `--log-format <pretty\|json\|ndjson>` | Logger output format. | `pretty` |
| `--no-log-timestamps` | Disable timestamps in pretty mode. | timestamps enabled |
| `--no-log-color` | Disable color in pretty mode. | color enabled |
| `--log-url <pattern>` | Filter log events by URL substring/regex. | unset |
| `--log-tab <id>` | Filter log events by tab ID. | unset |

## Shared global options

Also supports [Global flags](/docs/workflows/global-flags).

## Examples

### Start with default browser

<Frame>
  <iframe className="w-full aspect-video rounded-xl" src="https://www.youtube-nocookie.com/embed/voPbTvrVU9M?rel=0" title="Extension.js: extension start" loading="lazy" allow="encrypted-media; picture-in-picture; fullscreen" allowFullScreen />
</Frame>

<CodeGroup>
  ```bash npm theme={null}
  extension start
  ```

  ```bash pnpm theme={null}
  extension start
  ```

  ```bash yarn theme={null}
  extension start
  ```

  ```bash bun theme={null}
  extension start
  ```

  ```bash deno theme={null}
  extension start
  ```
</CodeGroup>

### Start in Firefox

<CodeGroup>
  ```bash npm theme={null}
  extension start --browser firefox
  ```

  ```bash pnpm theme={null}
  extension start --browser firefox
  ```

  ```bash yarn theme={null}
  extension start --browser firefox
  ```

  ```bash bun theme={null}
  extension start --browser firefox
  ```

  ```bash deno theme={null}
  extension start --browser firefox
  ```
</CodeGroup>

### Build and skip browser launch

<CodeGroup>
  ```bash npm theme={null}
  extension start --no-browser
  ```

  ```bash pnpm theme={null}
  extension start --no-browser
  ```

  ```bash yarn theme={null}
  extension start --no-browser
  ```

  ```bash bun theme={null}
  extension start --no-browser
  ```

  ```bash deno theme={null}
  extension start --no-browser
  ```
</CodeGroup>

## Behavior notes

* `start` does not run a dev server and does not provide hot module replacement (HMR) or watch mode.
* `start` is production-mode oriented. Use `dev` for iterative local development.
* For machine consumers, parse `dist/extension-js/<browser>/ready.json` instead of terminal text.

## Next steps

* Iterate quickly with [`dev`](/docs/commands/dev).
* Launch existing build output with [`preview`](/docs/commands/preview).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.