Extension.js – Build Browser Extensions Without Build Config
A CLI framework that handles Chrome, Edge, and Firefox browser extension development with zero config, built-in HMR, and Manifest V3 support. Quick setup.
TL;DR
TL;DR: Extension.js is a zero-config CLI for building Chrome, Edge, and Firefox extensions. One command scaffolds a project, one command runs it in all targets, and production builds are ready for the web store.
Source and Accuracy Notes
All claims verified from source. See links below.
- Project page: extension.js.org
- Source repository: github.com/extension-js/extension.js
- npm package: npmjs.com/package/extension
- License: MIT (verified via GitHub API
license.spdx_id) - HN launch thread: news.ycombinator.com/item?id=… — 381 points on launch
The Problem: Browser Extensions Have the Worst Dev Experience
Building a cross-browser extension in 2026 means juggling Manifest V3 differences between Chrome, Edge, and Firefox, managing separate build pipelines, and losing hot reload the moment you touch content scripts. Existing frameworks like Plasmo, WXT, and CRXJS help, but each brings its own trade-offs around configuration complexity and feature scope.
What Is Extension.js?
Extension.js is a cross-browser extension CLI that puts zero-config first. You run one command, pick from live templates, and your project is ready to develop and build — no webpack, no rollup, no plugins to maintain. It targets Chrome, Edge, and Firefox from a single codebase.
The README pitches it as the framework that “fixes” the browser extension dev experience. Key features:
- Hot Module Replacement for background, content, popup, and options scripts, including React, Vue, Svelte, and Preact
- Manifest V3 by default with automatic adapters for all three browsers
- One CLI for Chrome, Edge, Firefox, and any Chromium or Gecko binary
- Zero config — no webpack, no rollup, no plugins
- First-class TypeScript, React, Vue, Svelte, and Preact support
- Production builds with
extension build --zip, ready for the Chrome Web Store and Firefox Add-ons - Drop-in for existing extensions by adding it as a devDependency
Setup Workflow
Step 1: Create a new extension
npx extension@latest create my-extension
You’ll see a list of live templates you can run directly in the browser, including Vanilla JS, TypeScript, React, Vue, Svelte, and Preact.
Step 2: Run in development mode
cd my-extension
npm run dev
The CLI opens your extension in the target browser with HMR active. By default it uses your system Chrome, but you can override with a flag:
npm run dev -- --browser firefox
For managed browser binaries (useful in CI or if you don’t have Firefox installed locally):
npx extension install firefox
Then reference it with:
npm run dev -- --browser firefox --gecko-binary ~/.extension-dev/firefox/firefox-bin
Step 3: Build for production
npm run build
This outputs a /dist-zip folder with .zip files ready to upload to the Chrome Web Store or Firefox Add-ons.
Step 4: Try without installing
If you want to kick the tires before committing to a project install, Extension.js lets you run any GitHub sample directly:
npx extension dev https://github.com/extension-js/examples --template react
How It Differs from Existing Tools
The README makes a direct comparison with Plasmo, WXT, and CRXJS:
| Capability | Extension.js |
| :--------- | :----------- |
| Run any GitHub sample directly | extension dev https://github.com/.../sample |
| Managed browser binaries | extension install firefox |
| Cross-browser HMR for content scripts | Built in |
| Production zip for stores | extension build --zip |
| Framework agnostic | Vanilla, TS, React, Vue, Svelte, Preact |
Deeper Analysis
Manifest V3 and background scripts
Extension.js defaults to Manifest V3, which means service workers instead of persistent background pages. The CLI handles the manifest generation and ensures the background script lifecycle works correctly across Chrome’s stricter MV3 enforcement and Firefox’s more permissive approach.
Content script HMR
The killer feature for active development is that content script changes hot-reload without restarting the extension or reloading the tab. This is notoriously hard to get right in content scripts (as opposed to popup/options pages) and typically requires plugin glue with webpack or rollup. Extension.js bakes this in.
Framework choice
Unlike Plasmo (which is React-first) or WXT (which is TypeScript-first), Extension.js treats framework support as a first-class citizen with equal treatment across all six options. The templates at templates.extension.dev make this easy to preview before installing.
Practical Evaluation Checklist
- Create a new extension with one command
- Run
npm run dev— verify HMR fires on popup and content script edits - Switch browser with
--browser firefox - Run
npm run build— verify.zipoutput in/dist-zip - Add the package as a devDependency to an existing extension project — verify it doesn’t clobber an existing
manifest.json
Security Notes
Extension.js is a build tool, not a runtime dependency. It runs in your local development environment and produces static extension bundles. The security posture of the built extension depends entirely on your code and the permissions you request in the manifest. Review the generated manifest.json before publishing to any store.
FAQ
Q: Does it support Manifest V2 extensions? A: The project defaults to Manifest V3. MV2 support depends on browser vendor policies — Chrome has deprecated MV2, Firefox still supports it but the ecosystem is shifting. Check the Extension.js docs for MV2-specific configuration if you need it.
Q: Can I use this with an existing Chrome Extension?
A: Yes. Add extension as a devDependency, move your source to src/ if needed, and configure extension.config.js for any custom paths. The README calls this a “drop-in” experience.
Q: Does it work with bun or pnpm? A: Yes. The README explicitly states it works with npm, pnpm, yarn, and bun.
Q: How does it handle browser-specific APIs? A: Extension.js generates per-browser manifests and provides adapters for common API differences. For deep browser API differences, you’ll still need conditional code — the CLI doesn’t abstract away all browser runtime differences.
Conclusion
Extension.js solves the cross-browser extension dev experience by treating zero-config as a first-class constraint, not an afterthought. If you’ve been managing separate build pipelines for Chrome and Firefox, or losing hours to content script HMR调试, this CLI is worth a try. The npx extension@latest create flow gets you from zero to a running extension in under a minute.
For a full comparison against WXT and Plasmo, the Extension.js docs have a capability matrix and links to try each template live in the browser.
Related Posts
dev-tools
Automotive Skills Suite for AI Engineering
Evaluate Automotive Skills Suite for APQP, ASPICE, HARA, safety-plan, and DIA workflows with setup notes, governance risks, and SME review guidance.
5/28/2026
dev-tools
awesome-agentic-ai-zh Roadmap Guide
Explore awesome-agentic-ai-zh as a Chinese agentic AI learning roadmap, with setup notes, track selection, study workflow, and evaluation guidance.
5/28/2026
dev-tools
Baguette iOS Simulator Automation Guide
Set up Baguette for iOS Simulator automation, web dashboards, device farms, gesture input, streaming, and camera testing with Xcode caveats.
5/28/2026