Originally published on ExtensionLaunch.

Choosing between WXT vs Plasmo used to be a question of taste: Vite or Parcel, file conventions or React-first magic. In 2026 it's mostly a question of who is still shipping releases. Below is the short version of the comparison, the numbers behind it, and a six-step checklist if you decide to move an existing Plasmo project.

The numbers that decide it

All figures were checked in October 2026.

WXT Plasmo CRXJS
Type Framework Framework Vite plugin
Bundler Vite (6.3+, 7, 8) Parcel Vite (3 to 8)
Latest release 0.21.4 (Aug 11, 2026) 0.90.5 (May 17, 2025) 3.0.0 (Sep 24, 2026)
Weekly npm downloads (Oct 12–18) ~431k ~361k ~221k
UI frameworks Any React first, Vue/Svelte supported Any
Store ZIPs wxt zip plasmo build --zip No
Firefox sources ZIP Automatic No No
Store submission wxt submit (Chrome, Firefox, Edge) BPP GitHub Action No

The line that matters is "Latest release." Plasmo still installs, still works and still has a big install base. But a roughly 17-month gap with no npm release means any bundler conflict or Chrome API change you hit is yours to work around.

Where the developer experience actually differs

Project layout. WXT discovers entrypoints from an entrypoints/ folder and keeps content script options inside the file with defineContentScript. Popup and options pages are HTML files that mount your app. Plasmo uses named files (popup.tsx, content.ts) with an exported config, and its popup can be a bare React component export. That last trick is Plasmo's nicest convenience.

Dev loop. Both reload on change. WXT launches a browser with the extension already installed and applies HMR to UI pages; Plasmo gives you live reload plus React HMR.

Extension APIs. WXT exports a browser object that prefers globalThis.browser and falls back to globalThis.chrome, so promise-based code runs without webextension-polyfill. Plasmo ships its own wrappers, @plasmohq/storage and @plasmohq/messaging.

Cross-browser builds. The flags look different:

# WXT: Firefox and Safari default to MV2, add --mv3 if you want MV3 wxt build -b firefox --mv3 wxt zip -b firefox # extension ZIP + sources ZIP for AMO # Plasmo plasmo build --target=firefox-mv2 --zip 

In code, WXT exposes import.meta.env.FIREFOX for per-browser branches, while Plasmo sets process.env.PLASMO_BROWSER.

Safari. wxt build -b safari writes to .output/safari-mv2 (or safari-mv3). You still run Apple's safari-web-extension-packager on that folder, because WXT doesn't generate the macOS/iOS wrapper app.

So which one?

  • Starting a new extension: WXT. It's actively released, works with any UI library, and covers the whole path from build to store submission.
  • Chrome-first Vite app, minimal tooling: CRXJS. It keeps manifest.json as the source of truth and handles build and hot reload. You write your own zip and release script.
  • Existing Plasmo extension that works fine: no need to rush. Plan a migration when you hit a bundler conflict or need a fix that hasn't shipped.

Migrating from Plasmo to WXT in 6 steps

  1. Install wxt, move every entrypoint into entrypoints/, and fold named exports like Plasmo's config into WXT's default export.
  2. Give popup and options pages an HTML file that mounts your React/Vue/Svelte app. WXT won't render a .tsx page file on its own.
  3. Move assets/* to public/ and swap Plasmo's CSUI for createContentScriptUi.
  4. Rename env vars: PLASMO_PUBLIC_* becomes WXT_* or VITE_*.
  5. Replace --tag with --mode. Plasmo's remote code imports have no WXT counterpart, so install those dependencies from npm and bundle them.
  6. Diff your old production manifest.json against .output/*/manifest.json. Permissions, host permissions and the key field must match, or users get a fresh permission prompt.

Your extension ID doesn't change. The ID belongs to the Chrome Web Store item, not the framework. Upload the new build to the same item with a higher version number and users get a normal update, with their settings and your reviews intact.

On bundle size, measure your own build rather than trusting anecdotes. WXT prints each output file's size, so a before/after check takes a minute. One 2024 migration (Jetwriter) reported its ZIP going from 700 KB to 400 KB, but your mileage depends on your code.

Key takeaways

  • WXT and Plasmo are both MIT-licensed frameworks; the real difference in 2026 is release activity.
  • WXT is the safer default for new projects and the only one of the three with automatic Firefox sources ZIPs and a built-in wxt submit command for Chrome, Firefox and Edge.
  • CRXJS is a Vite plugin, not a framework, so plan your own packaging and publishing.
  • Migrating keeps your extension ID; the step to get right is the manifest diff, so users don't see new permission prompts.

The original article has the full side-by-side, the FAQ and more detail on each step: WXT vs Plasmo framework comparison and migration guide. If you're getting close to shipping, ExtensionLaunch has more guides on launching and growing a browser extension.

Which framework are you building your current extension with, and what's the one thing that would make you switch?