plasmo vs wxt
Building Modern Browser Extensions with Developer Tools
plasmowxtSimilar Packages:

Building Modern Browser Extensions with Developer Tools

plasmo and wxt are build tools designed to simplify browser extension development. They handle cross-browser compatibility, bundling, and hot reloading. plasmo acts as a full framework with strong conventions, especially for React. wxt functions as a toolkit built on Vite, offering flexibility for various frontend frameworks.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
plasmo013,010179 kB367a year agoMIT
wxt09,736324 kB22018 days agoMIT

Plasmo vs Wxt: Architecture, DX, and Extension Development Compared

Both plasmo and wxt aim to solve the same problem โ€” browser extension development is historically painful. They abstract away manifest management, cross-browser quirks, and bundling complexity. However, they take different approaches to structure and flexibility. Let's compare how they handle real engineering tasks.

โš™๏ธ Project Setup and Configuration

plasmo uses a dedicated config file with strong defaults.

  • You define settings in plasmo.config.ts.
  • It assumes a React-centric structure but supports others.
// plasmo: plasmo.config.ts
import type { PlasmoConfig } from "plasmo";

const config: PlasmoConfig = {
  manifest: {
    permissions: ["storage", "tabs"]
  }
};

export default config;

wxt uses a Vite-based config with modular entrypoints.

  • You define settings in wxt.config.ts.
  • It relies on file conventions in the entrypoints folder.
// wxt: wxt.config.ts
import { defineConfig } from "wxt";

export default defineConfig({
  manifest: {
    permissions: ["storage", "tabs"]
  }
});

๐Ÿ“œ Content Scripts: Mounting and Logic

plasmo treats content scripts as modules with exported config.

  • You create a content.ts file.
  • You export a config object to define matches.
  • UI mounting often uses helper functions provided by the framework.
// plasmo: content.ts
export const config = {
  matches: ["<all_urls>"]
};

export default async function main() {
  const container = document.createElement("div");
  container.id = "my-app";
  document.body.appendChild(container);
  // Render React/Vue app into container
}

wxt uses a definition function for content scripts.

  • You create entrypoints/content.ts.
  • You use defineContentScript to set matches and logic.
  • It provides built-in helpers for UI integration.
// wxt: entrypoints/content.ts
import { defineContentScript } from "wxt/sandbox";

export default defineContentScript({
  matches: ["<all_urls>"],
  async main(ctx) {
    const container = document.createElement("div");
    container.id = "my-app";
    document.body.appendChild(container);
    // Render app into container
  }
});

๐Ÿง  Background Workers and Service Workers

plasmo uses a dedicated background.ts file.

  • It handles service worker lifecycle automatically.
  • You write standard TypeScript logic.
// plasmo: background.ts
export default function Background() {
  chrome.tabs.onUpdated.addListener((tabId, changeInfo) => {
    console.log("Tab updated", tabId);
  });
}

wxt uses a definition function in the entrypoints folder.

  • You create entrypoints/background.ts.
  • You specify the type (module or persistent) explicitly.
// wxt: entrypoints/background.ts
import { defineBackground } from "wxt/sandbox";

export default defineBackground({
  type: "module",
  main() {
    chrome.tabs.onUpdated.addListener((tabId, changeInfo) => {
      console.log("Tab updated", tabId);
    });
  }
});

๐Ÿ–ฅ๏ธ UI Pages: Popups and Options

plasmo uses single-file components for UI surfaces.

  • A popup.tsx file becomes your extension popup.
  • It supports React components directly.
// plasmo: popup.tsx
import { useState } from "react";

export default function Popup() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}

wxt separates HTML and logic in the entrypoints folder.

  • You create entrypoints/popup/index.html.
  • You link a TypeScript entry file for logic.
<!-- wxt: entrypoints/popup/index.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Popup</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="./main.ts"></script>
  </body>
</html>

๐ŸŒ Cross-Browser Builds

plasmo handles browser targets via command flags.

  • You specify the target when building.
  • It adjusts the manifest automatically.
# plasmo: Build for Firefox
plasmo build --target=firefox-mv2

wxt handles browser targets via config or flags.

  • You specify the browser in the build command.
  • It supports Chrome, Firefox, Safari, and Edge.
# wxt: Build for Firefox
wxt build --browser firefox

๐Ÿค Similarities: Shared Ground Between Plasmo and Wxt

While the differences are clear, both tools share many core ideas and capabilities. Here are key overlaps:

1. โšก Hot Module Replacement (HMR)

  • Both support fast refresh during development.
  • Changes reflect instantly without reloading the extension manually.
// Both: Development server handles updates
// No extra config needed for basic HMR

2. ๐Ÿ“ฆ Manifest Management

  • Both generate manifest.json automatically.
  • You define permissions in config, not in a static file.
// Both: Define permissions in config
// plasmo.config.ts or wxt.config.ts
permissions: ["storage"]

3. ๐Ÿ› ๏ธ TypeScript Support

  • Both are built with TypeScript first.
  • Full type safety for Chrome APIs and browser events.
// Both: Typed Chrome API
chrome.storage.local.get({ key: "value" }, (result) => {
  // result is typed
});

4. ๐Ÿ”Œ Asset Handling

  • Both handle images, fonts, and static assets.
  • Assets are bundled and referenced correctly in the manifest.
// Both: Import assets directly
import logo from "~/assets/logo.png";

5. ๐Ÿš€ Deployment Ready

  • Both produce zip files ready for store submission.
  • Support for multiple build profiles (dev, prod, staging).
# Both: Build for production
plasmo build
wxt build

๐Ÿ“Š Summary: Key Similarities

FeatureShared by Plasmo and Wxt
Core Techโšก Vite-based bundling
Language๐Ÿ“˜ TypeScript first
Manifest๐Ÿ“„ Auto-generated from config
Development๐Ÿ”„ Hot Module Replacement
Assets๐Ÿ–ผ๏ธ Automatic bundling
Targets๐ŸŒ Chrome, Firefox, Edge, Safari

๐Ÿ†š Summary: Key Differences

Featureplasmowxt
Philosophy๐Ÿ—๏ธ Opinionated Framework๐Ÿงฐ Flexible Toolkit
Config Fileplasmo.config.tswxt.config.ts
Content ScriptsExport config objectdefineContentScript function
UI StructureSingle file componentsHTML + TS entrypoints
Framework FocusReact-first (supports others)Framework-neutral (Vite plugins)
Backgroundbackground.ts functiondefineBackground function

๐Ÿ’ก The Big Picture

plasmo is like a pre-fabricated house ๐Ÿ  โ€” great for teams that want to move fast with React and prefer standard structures. Ideal for startups, marketing extensions, and teams already invested in the React ecosystem.

wxt is like a custom build kit ๐Ÿ› ๏ธ โ€” perfect for teams who want control over every file and use various frameworks. Shines in complex enterprise extensions, multi-framework repos, and projects needing specific Vite plugins.

Final Thought: Despite their different approaches, both tools make extension development significantly easier than the vanilla workflow. Choose based on your team's framework preference and desire for convention versus control.

How to Choose: plasmo vs wxt

  • plasmo:

    Choose plasmo if your team uses React heavily and prefers a structured framework with built-in UI components for extension surfaces. It is ideal for projects that benefit from convention over configuration and need a stable, opinionated setup for content scripts and popups.

  • wxt:

    Choose wxt if you want Vite-based speed, support for multiple frameworks like Vue or Svelte, and fine-grained control over entrypoints. It is suitable for teams that value modular architecture and want to leverage the wider Vite plugin ecosystem.

README for plasmo

plasmo logo

See License NPM Install Follow PlasmoHQ on Twitter Watch our Live DEMO every Friday Join our Discord for support and chat about our projects

English | ็ฎ€ไฝ“ไธญๆ–‡ | Tiแบฟng Viแป‡t | Deutsch | French | Indonesian | ะ ัƒััะบะธะน | Turkish | ๆ—ฅๆœฌ่ชž | ํ•œ๊ตญ์–ด

Production Cloud: We've built a cloud offering for browser extensions called Itero. Check it out if you want instant beta testing and more awesome features.

Plasmo Framework

The Plasmo Framework is a battery-packed browser extension SDK made by hackers for hackers. Build your product and stop worrying about config files and the odd peculiarities of building browser extensions.

It's like Next.js for browser extensions!

CLI Demo

Highlighted Features

And many, many more! ๐Ÿš€

System Requirements

  • Node.js 16.x or later
  • MacOS, Windows, or Linux
  • (Strongly Recommended) pnpm

Examples

We have examples showcasing how one can use Plasmo with Firebase Authentication, Redux, Supabase authentication, Tailwind, and many more. To check them out, visit our examples repository.

Documentation

Check out the documentation to get a more in-depth view into the Plasmo Framework.

Browser Extensions Book

For a more in-depth view into how browser extensions work, and how to develop them, we highly recommend Matt Frisbie's new book "Building Browser Extensions"

Usage

pnpm create plasmo example-dir
cd example-dir
pnpm dev

The road ahead is filled with many turns.

  • Popup changes go in popup.tsx
  • Options page changes go in options.tsx
  • Content script changes go in content.ts
  • Background service worker changes go in background.ts

Directories

You can also organize these files in their own directories:

ext-dir
โ”œโ”€โ”€โ”€assets
|   โ””โ”€โ”€โ”€icon.png
โ”œโ”€โ”€โ”€popup
|   โ”œโ”€โ”€โ”€index.tsx
|   โ””โ”€โ”€โ”€button.tsx
โ”œโ”€โ”€โ”€options
|   โ”œโ”€โ”€โ”€index.tsx
|   โ”œโ”€โ”€โ”€utils.ts
|   โ””โ”€โ”€โ”€input.tsx
โ”œโ”€โ”€โ”€contents
|   โ”œโ”€โ”€โ”€site-one.ts
|   โ”œโ”€โ”€โ”€site-two.ts
|   โ””โ”€โ”€โ”€site-three.ts
...

Finally, you can also avoid putting source code in your root directory by putting them in a src sub-directory, following this guide. Note that assets and other config files will still need to be in the root directory.

Supported Browsers

To see a list of supported browser targets, please refer to our documentation here.

Community

The Plasmo community can be found on Discord. This is the appropriate channel to get help with using the Plasmo Framework.

Our Code of Conduct applies to all Plasmo community channels.

Contributing

Please see the contributing guidelines to learn more.

A big thanks to all of our amazing contributors โค๏ธ

Feel free to join the fun and send a PR!

Plasmo Framework

Plasmo Examples

Plasmo Storage

Browser Platform Publisher

Disclaimer

Plasmo is currently alpha software, and some things might change from version to version, so please be mindful and use it at your own risk.

License

MIT โญ Plasmo