OpenRadar

Project · TypeScript · Added June 18, 2026

extension.js

Extension.js is a zero-config cross-browser extension framework with HMR, TypeScript, and first-class React/Vue/Svelte support. Build Chrome, Edge, and Firefox extensions without build configuration.

5,003 stars 128 forks View on GitHub

Extension.js

Overview

Extension.js is a zero-config CLI framework for building cross-browser extensions. It hit 5,000 GitHub stars in mid-2026 after a Hacker News front-page post drew 381 points, and it’s been downloaded roughly 17,500 times from npm in the past month. Those numbers are modest compared to something like Vite, but for the browser extension tooling space — which has been genuinely neglected — they’re significant.

The project is maintained by Cezar Augusto, a developer who’s been working on extension developer experience since 2020. The original motivation was simple: building browser extensions still sucks. Manifest V3 fragmentation, browser-specific quirks, no hot reload for content scripts, separate build pipelines for every target. If you’ve ever tried to build a Chrome extension with React and TypeScript, you know the pain. You end up configuring webpack or rollup, fighting with content script injection, and maintaining separate configs for Chrome and Firefox.

Extension.js collapses all of that into a single CLI. npx extension@latest create my-extension scaffolds a project. npm run dev starts it with hot module replacement across background, content, popup, and options scripts. extension build --zip produces a production bundle ready for the Chrome Web Store or Firefox Add-ons. No build config files to maintain. No plugins to wrangle. It just works.

Why it matters

The browser extension ecosystem is quietly massive. Chrome alone has over 175,000 extensions, and the market is growing as AI-powered browser tools become mainstream. Every AI assistant, ad blocker, password manager, and developer tool ships as a browser extension. Yet the developer experience has lagged years behind the rest of the web platform.

While frontend frameworks like Next.js, Remix, and Astro have invested heavily in DX, extension developers have been stuck with raw webpack configs or early-generation tools that solve half the problem. Plasmo came first and did good work, but its opinionated structure doesn’t fit every project. WXT improved on the concept but still requires configuration. CRXJS focused on Vite integration but doesn’t handle Firefox well. Extension.js takes a different approach — it’s framework-agnostic, browser-agnostic, and genuinely zero-config.

The timing matters too. Manifest V3 migration is forcing every extension developer to revisit their build tooling. Chrome deprecated Manifest V2 in 2024, and Firefox is following suit. If you’re rewriting your extension anyway, you might as well modernize the toolchain. Extension.js is positioned as the path of least resistance for that migration.

Key Features

Cross-Browser HMR for Content Scripts. This is the killer feature. Hot module replacement for content scripts is genuinely hard — you’re injecting code into third-party web pages, and most build tools give up on reloading them without a full page refresh. Extension.js handles it natively. Edit your React component in a content script, see the change instantly without losing page state. This alone saves hours per week during development.

Zero Configuration. No webpack.config.js, no vite.config.ts, no manifest.json editing. Extension.js auto-generates the manifest based on your project structure. It detects which scripts you have (background, content, popup, options) and builds the manifest accordingly. You can override anything, but the defaults work for 90% of projects.

Framework-Agnostic Templates. The CLI scaffolds projects in Vanilla JS, TypeScript, React, Vue, Svelte, and Preact. You pick your framework at creation time and get a working extension with proper typing, HMR, and browser APIs. There’s no framework lock-in — you can mix and match. A popup in React with a content script in vanilla TypeScript works fine.

Managed Browser Binaries. extension install firefox downloads an isolated Firefox build for development. No need to have Firefox installed on your system. extension install --browser=all grabs Chrome, Edge, and Firefox in one go. This is especially useful in CI environments where you need clean browser instances for testing.

Production Store Bundles. extension build --zip produces a ZIP file ready for upload to the Chrome Web Store, Edge Add-ons, or Firefox AMO. There’s also --zip-source for store source-code review requirements (some stores ask for your source code), and --polyfill for cross-browser webextension API compatibility. The build pipeline handles Manifest V3 differences between browsers automatically.

Run Any GitHub Sample Directly. Point the CLI at any Chrome extension sample on GitHub and run it immediately: npx extension dev https://github.com/GoogleChrome/chrome-extensions-samples/tree/main/functional-samples/sample.page-redder. This is great for learning, debugging, and testing third-party extensions without cloning repos.

Drop-In Integration. Already have an extension project? Install Extension.js as a dev dependency and add three scripts to your package.json. It replaces your existing build pipeline without restructuring your codebase. This migration path is realistic — you don’t need to start from scratch.

Use Cases

Pros and Cons

Pros:

Cons:

Getting Started

# Create a new React extension
npx extension@latest create my-extension --template react
cd my-extension

# Start development with HMR
npm run dev

# Build for production
npx extension@latest build --zip

# Run a Chrome sample directly
npx extension@latest dev https://github.com/GoogleChrome/chrome-extensions-samples/tree/main/functional-samples/sample.page-redder

Add to an existing project:

npm install extension@latest --save-dev
{
  "scripts": {
    "dev": "extension dev",
    "build": "extension build --zip",
    "preview": "extension preview"
  }
}

Alternatives

Plasmo — The most established browser extension framework with a larger community and more integrations (e.g., built-in messaging, storage abstraction, background jobs). Plasmo uses an opinionated file-based routing system that works well for standard extensions but can feel constraining for complex architectures. Choose Plasmo if you want more built-in abstractions and don’t mind the opinionation.

WXT — A Vite-powered extension framework that’s gained traction for its flexibility and modern toolchain. WXT gives you more control over the build process and supports modules, auto-imports, and i18n out of the box. Choose WXT if you’re already invested in the Vite ecosystem and want fine-grained configuration.

CRXJS — A Vite plugin focused on Chrome extension development with excellent HMR support. CRXJS is lighter weight than a full framework but doesn’t handle Firefox or cross-browser manifest differences. Choose CRXJS if you only target Chrome and want minimal tooling overhead.

Verdict

Extension.js fills a real gap. Browser extension development has been stuck in a webpack-era time warp while the rest of the frontend ecosystem moved on. The zero-config approach with genuine cross-browser HMR for content scripts is the right abstraction level — it handles the hard parts (manifest generation, browser differences, content script injection) and gets out of your way for everything else.

It’s not the most mature option. Plasmo has more integrations and a larger community. WXT offers more configuration flexibility. But Extension.js has the cleanest mental model and the lowest barrier to entry. If you’re a React or Vue developer who needs to build a browser extension and doesn’t want to learn extension-specific build tooling, this is where I’d start. The 5,000 stars and HN traction suggest the developer community agrees. Keep an eye on Safari support — once that lands, the cross-browser story becomes truly complete.

Related

Shared tags