Skip to main content
Bun works as the package manager and the script runner for an Extension.js project. Extension.js detects Bun, records it in package.json, and prints Bun commands in its own output. The Extension.js CLI itself runs on Node. That split is the whole answer to the question below.

Can I use Bun instead of Node?

For your project, yes. For the CLI process, no. Bun stays your interface. Node stays the runtime that executes the CLI. You need both installed.

Create a project with Bun

Extension.js sees that Bun invoked it. The next steps that it prints name Bun:
The generated package.json pins the manager that you used:
package.json

Install and build

That writes a bun.lock file. Extension.js reads the lockfile on later runs to keep choosing Bun.
The scripts that the scaffolder writes are manager-agnostic. Each one calls the extension binary, so bun run dev, bun run build, and bun run preview all work.

Why the CLI needs Node

The published packages declare "engines": {"node": ">=22.12"}. The CLI checks process.versions.node at startup and stops when the version is too low. Bun reports a Node compatibility version that is lower than that floor. Forcing the Bun runtime therefore trips the guard:
The version in that message is the Node compatibility version that Bun reports, not the Node that you installed. Drop --bun and the same command works. Plain bunx respects the #!/usr/bin/env node shebang on the CLI binary, so the process runs on Node while Bun handles resolution and caching.

How Extension.js detects Bun

Detection reads the project, not the command that you typed. Three signals feed it:
  • A bun.lock or bun.lockb lockfile at the project root.
  • A packageManager field in package.json that names bun.
  • The npm_config_user_agent environment variable that Bun sets when it runs a script.
Extension.js supports npm, pnpm, yarn, bun, and deno. When no signal is present, it probes your PATH in the order pnpm, yarn, bun.

Automatic dependency installs

extension dev and extension build install missing dependencies before they compile. The install runs through the manager that was detected, and it passes --ignore-scripts. A postinstall script in a dependency therefore does not run during that step.

Caveats

  • Bun-specific runtime APIs such as Bun.file do not belong in extension code. That code runs in the browser.
  • Extension.js writes no Bun-specific scripts. The dev, build, and preview scripts are the same for every manager.
  • A template that you import through extension create ships without a lockfile. Extension.js strips bun.lock and bun.lockb from it. Your own install then decides the tree.

Next steps