Skip to main content
Extension.js and CRXJS both turn a manifest.json and modern source into a working extension. Extension.js is a CLI framework that owns its bundler. CRXJS is a plugin that adds extension output to a Vite setup you own. This page is a factual comparison so you can choose based on your project.

Which should you choose?

Choose Extension.js if…

  • You want one CLI that opens the browser, reloads on save, builds per browser, and zips for the stores.
  • You ship to Chrome, Edge, Firefox, and Safari from one manifest.json.
  • You want no bundler config in your project.

Choose CRXJS if…

  • You already have a Vite app and want extension output added to it.
  • You depend on Vite plugins and want to keep them.
  • You are fine loading the unpacked build in the browser yourself.

At a glance

Mental model

Extension.js owns the bundler. You write a manifest.json and reference real files. The CLI compiles them, filters the manifest for each browser, and packages the result. You never configure the bundler, and bundler upgrades are the framework’s job. CRXJS lives inside your bundler. You add crx({ manifest }) to vite.config, and Vite builds the extension next to the rest of your app. You keep full control of Vite and every Vite plugin. Each Vite major needs CRXJS compatibility work, which is why the Vite 8 fileName error existed for a while.

Dev loop

Extension.js

The CLI opens each browser with a fresh profile and the extension loaded. A save reloads the right surface: HMR for pages, a targeted reload for content scripts and the service worker.

CRXJS

Vite starts its dev server and writes the extension to the output folder. You load that folder unpacked in the browser once, then HMR updates pages and content scripts.

Cross-browser builds

  • Extension.js builds every browser from one source with --browser.
  • Browser differences go in browser-prefixed manifest fields, such as chrome: and firefox:.
  • CRXJS builds one target per run, and browser: 'firefox' in the plugin options gives a Firefox build.
  • The CRXJS docs have no Safari guide.

Packaging

Extension.js writes dist/<browser> and a zip per browser next to it. With CRXJS, you zip Vite’s output folder with your own script or tool.

When to migrate

Move from CRXJS to Extension.js when you want the CLI to launch browsers, build several browsers in one run, or ship to Safari. Your components, chrome.* calls, and styles carry over. Migrate from CRXJS walks through it step by step.

See also