> ## Documentation Index
> Fetch the complete documentation index at: https://extension.js.org/llms.txt
> Use this file to discover all available pages before exploring further.

# The cross-browser extension framework

> Build browser extensions for Chrome, Edge, and Firefox from one project with manifest compilation, fast reloads on save, and store-ready packaging.

<script
  type="application/ld+json"
  dangerouslySetInnerHTML={{
__html: JSON.stringify({
  "@context": "https://schema.org",
  "@type": "SoftwareApplication",
  name: "Extension.js",
  applicationCategory: "DeveloperApplication",
  operatingSystem: "Windows, macOS, Linux",
  description:
    "Cross-browser extension framework for Chrome, Edge, and Firefox. One project, one manifest.json, browser-specific output, and reload behavior tuned for service workers and content scripts.",
  url: "https://extension.js.org",
  downloadUrl: "https://www.npmjs.com/package/extension",
  softwareVersion: "latest",
  offers: {
    "@type": "Offer",
    price: "0",
    priceCurrency: "USD",
  },
  author: {
    "@type": "Organization",
    name: "Extension.js authors",
    url: "https://github.com/extension-js",
  },
  license: "https://github.com/extension-js/extension.js/blob/main/LICENSE",
}),
}}
/>

<script
  type="application/ld+json"
  dangerouslySetInnerHTML={{
__html: JSON.stringify({
  "@context": "https://schema.org",
  "@type": "FAQPage",
  mainEntity: [
    {
      "@type": "Question",
      name: "What is a browser extension?",
      acceptedAnswer: {
        "@type": "Answer",
        text: "A browser extension is software that adds features to Chrome, Firefox, Edge, or another browser. Extensions inject UI, react to browser events, and call privileged APIs the page itself cannot.",
      },
    },
    {
      "@type": "Question",
      name: "Is Extension.js a Chrome extension framework?",
      acceptedAnswer: {
        "@type": "Answer",
        text: "Yes. Extension.js works as a Chrome extension framework, and also as a Firefox and Edge extension framework, from the same project. Choose a target with --browser=chrome, --browser=firefox, or --browser=edge.",
      },
    },
    {
      "@type": "Question",
      name: "How does Extension.js handle hot module replacement during development?",
      acceptedAnswer: {
        "@type": "Answer",
        text: "Run npx extension dev and the CLI watches your project for changes. Edits to popups, content scripts, service workers, and options pages trigger the fastest safe update path: HMR when supported, targeted reloads otherwise.",
      },
    },
    {
      "@type": "Question",
      name: "How do I build one extension for Chrome, Edge, and Firefox?",
      acceptedAnswer: {
        "@type": "Answer",
        text: "Extension.js compiles a single codebase into browser-specific output. One set of commands produces correctly packaged builds for Chrome, Edge, Firefox, and other Chromium-based browsers. Each build gets the right manifest format, paths, and platform adjustments.",
      },
    },
    {
      "@type": "Question",
      name: "Can I use React, Preact, Vue, Svelte, or TypeScript?",
      acceptedAnswer: {
        "@type": "Answer",
        text: "Yes. Extension.js ships production-ready templates for React, Preact, Vue, Svelte, TypeScript, and plain JavaScript. Framework choice does not affect the core workflow.",
      },
    },
    {
      "@type": "Question",
      name: "Does Extension.js support Manifest V3?",
      acceptedAnswer: {
        "@type": "Answer",
        text: "Yes. The toolchain is built around Manifest V3 and the constraints browser stores enforce today: service workers, declarative APIs, updated permissions, and stricter packaging.",
      },
    },
    {
      "@type": "Question",
      name: "Is Extension.js free to use?",
      acceptedAnswer: {
        "@type": "Answer",
        text: "Yes. Extension.js is open source under the MIT license. There is no paid tier or usage cap.",
      },
    },
  ],
}),
}}
/>

<div className="mx-auto flex w-full max-w-6xl flex-col gap-24 px-6 py-16 sm:py-24">
  <section className="flex flex-col items-center text-center gap-8">
    {/* Browser dock logo grid (two rows) */}

    <div className="ext-dock mx-auto w-full">
      <div className="ext-dock-row ext-dock-row-top">
        <div className="ext-dock-tile">
          <img src="https://media.extension.land/logos/browsers/brave.svg" alt="Brave" style={{ padding: "5%" }} />
        </div>

        <div className="ext-dock-tile">
          <img src="https://media.extension.land/logos/browsers/chrome.svg" alt="Chrome" />
        </div>

        <div className="ext-dock-tile plain">
          <img src="https://media.extension.land/track/extension-js.png" alt="Extension.js" />
        </div>

        <div className="ext-dock-tile">
          <img src="https://media.extension.land/logos/browsers/edge.svg" alt="Edge" />
        </div>

        <div className="ext-dock-tile" style={{ border: "none" }}>
          <img src="https://media.extension.land/logos/browsers/safari.svg" alt="Safari" style={{ padding: 0 }} />
        </div>
      </div>

      <div className="ext-dock-row ext-dock-row-bottom">
        <div className="ext-dock-tile">
          <img src="https://media.extension.land/logos/browsers/opera.svg" alt="Opera" style={{ padding: "5%" }} />
        </div>

        <div className="ext-dock-tile">
          <img src="https://media.extension.land/logos/browsers/firefox.svg" alt="Firefox" />
        </div>

        <div className="ext-dock-tile">
          <img src="https://media.extension.land/logos/browsers/chromium.svg" alt="Chromium" />
        </div>

        <div className="ext-dock-tile">
          <img src="https://mintcdn.com/extensionjs/rnXP2INmBiIBB-KO/images/waterfox.png?fit=max&auto=format&n=rnXP2INmBiIBB-KO&q=85&s=ed1003490d829e4001d03e371c0ca8e6" alt="Waterfox" style={{ borderRadius: "50%" }} width="1280" height="1024" data-path="images/waterfox.png" />
        </div>
      </div>
    </div>

    <h1 className="text-5xl sm:text-6xl lg:text-[4rem] font-semibold tracking-tight leading-tight max-w-3xl text-neutral-900 dark:text-white">
      The cross-browser extension framework
    </h1>

    <p className="text-lg sm:text-xl text-gray-600 dark:text-gray-300 max-w-xl leading-relaxed">
      Build browser extensions across all major browsers with one modern
      workflow. Extension.js handles manifest compilation, browser-specific
      output, and packaging.
    </p>

    <div className="ext-hero-badges">
      <a href="https://github.com/extension-js/extension.js" target="_blank" rel="noreferrer" aria-label="GitHub stars">
        <img src="https://img.shields.io/github/stars/extension-js/extension.js?style=flat&logo=github&logoColor=white&color=0e62f7&labelColor=0b1220" alt="GitHub stars" loading="lazy" />
      </a>

      <a href="https://www.npmjs.com/package/extension" target="_blank" rel="noreferrer" aria-label="npm weekly downloads">
        <img src="https://img.shields.io/npm/dw/extension?style=flat&logo=npm&logoColor=white&color=0e62f7&labelColor=0b1220" alt="npm weekly downloads" loading="lazy" />
      </a>

      <a href="https://www.npmjs.com/package/extension" target="_blank" rel="noreferrer" aria-label="npm version">
        <img src="https://img.shields.io/npm/v/extension?style=flat&logo=npm&logoColor=white&color=0e62f7&labelColor=0b1220" alt="latest version on npm" loading="lazy" />
      </a>

      <a href="https://github.com/extension-js/extension.js/blob/main/LICENSE" target="_blank" rel="noreferrer" aria-label="MIT license">
        <img src="https://img.shields.io/github/license/extension-js/extension.js?style=flat&color=0e62f7&labelColor=0b1220" alt="MIT license" loading="lazy" />
      </a>
    </div>

    <div className="ext-hero-cmd">
      <span className="ext-hero-cmd-prompt" aria-hidden="true">
        \$
      </span>

      <code className="ext-hero-cmd-code">
        npx extension\@latest create my-extension
      </code>

      <button
        type="button"
        className="ext-hero-cmd-copy"
        aria-label="Copy command"
        onClick={(e) => {
      navigator.clipboard.writeText(
        "npx extension@latest create my-extension",
      );
      const el = e.currentTarget;
      const original = el.innerText;
      el.innerText = "Copied";
      setTimeout(() => {
        el.innerText = original;
      }, 1500);
    }}
      >
        Copy
      </button>
    </div>

    <div className="flex flex-wrap items-center justify-center gap-3">
      <a href="/docs" className="inline-flex items-center gap-3 rounded-lg bg-[#0e62f7] px-12 py-4 text-white text-lg font-semibold hover:opacity-90 transition no-underline">
        Get started ⏵⏵⏵
      </a>

      <a href="/docs/compare/extension-js-vs-wxt" className="inline-flex items-center gap-3 rounded-lg border border-gray-300 dark:border-neutral-700 px-12 py-4 text-neutral-900 dark:text-white text-lg font-semibold hover:opacity-90 transition no-underline">
        Compare frameworks ⏵
      </a>
    </div>
  </section>

  <section className="w-full">
    <div className="ext-codepreview">
      <div className="ext-codepreview-text">
        <h2 className="text-3xl sm:text-4xl font-semibold tracking-tight">
          One manifest.json.<br />All browsers.
        </h2>

        <p className="text-gray-600 dark:text-gray-400 mt-3 text-lg leading-relaxed max-w-md">
          Browser-prefixed keys (<code>chrome:</code>, <code>firefox:</code>,{" "}
          <code>edge:</code>) filter at compile time. Unprefixed keys apply
          everywhere.
        </p>

        <div className="mt-6 flex flex-wrap gap-3">
          <a href="/docs/features/browser-specific-fields" className="text-[#0e62f7] hover:opacity-80 font-medium no-underline">
            Read the full pattern ⏵
          </a>
        </div>
      </div>

      <pre className="ext-codepreview-code">
        <code>
          <span className="ext-cp-punc">
            {"{"}
          </span>

          {"\n"}

          {"  "}

          <span className="ext-cp-key">"manifest\_version"</span>
          <span className="ext-cp-punc">:</span>{" "}
          <span className="ext-cp-num">3</span>
          <span className="ext-cp-punc">,</span>

          {"\n"}

          {"  "}

          <span className="ext-cp-key">"name"</span>
          <span className="ext-cp-punc">:</span>{" "}
          <span className="ext-cp-str">"My Extension"</span>
          <span className="ext-cp-punc">,</span>

          {"\n"}

          {"  "}

          <span className="ext-cp-key">"version"</span>
          <span className="ext-cp-punc">:</span>{" "}
          <span className="ext-cp-str">"1.0.0"</span>
          <span className="ext-cp-punc">,</span>

          {"\n"}

          {"  "}

          <span className="ext-cp-key">"action"</span>
          <span className="ext-cp-punc">:</span>{" "}

          <span className="ext-cp-punc">
            {"{"}
          </span>

          <span className="ext-cp-key"> "default\_popup"</span>
          <span className="ext-cp-punc">:</span>{" "}
          <span className="ext-cp-str">"popup.html"</span>{" "}

          <span className="ext-cp-punc">
            {"}"}
          </span>

          <span className="ext-cp-punc">,</span>

          {"\n"}

          {"  "}

          <span className="ext-cp-prefix">"chrome:background"</span>
          <span className="ext-cp-punc">:</span>{" "}

          <span className="ext-cp-punc">
            {"{"}
          </span>

          <span className="ext-cp-key"> "service\_worker"</span>
          <span className="ext-cp-punc">:</span>{" "}
          <span className="ext-cp-str">"sw\.ts"</span>{" "}

          <span className="ext-cp-punc">
            {"}"}
          </span>

          <span className="ext-cp-punc">,</span>

          {"\n"}

          {"  "}

          <span className="ext-cp-prefix">"firefox:background"</span>
          <span className="ext-cp-punc">:</span>{" "}

          <span className="ext-cp-punc">
            {"{"}
          </span>

          <span className="ext-cp-key"> "scripts"</span>
          <span className="ext-cp-punc">:</span>{" "}
          <span className="ext-cp-punc">\[</span>
          <span className="ext-cp-str">"sw\.ts"</span>
          <span className="ext-cp-punc">]</span>{" "}

          <span className="ext-cp-punc">
            {"}"}
          </span>

          {"\n"}

          <span className="ext-cp-punc">
            {"}"}
          </span>
        </code>
      </pre>
    </div>
  </section>

  <section className="w-full">
    <div className="rounded-3xl bg-neutral-100 dark:bg-neutral-950 ring-1 ring-black/5 dark:ring-white/5 px-8 py-12 sm:px-14 sm:py-16 flex flex-col sm:flex-row items-start gap-10 text-left">
      <div className="shrink-0 aspect-square w-24 sm:w-28">
        <img src="https://media.extension.land/track/extension-js.png" alt="Extension.js" width="112" height="112" className="block w-full h-full object-contain" />
      </div>

      <div className="flex flex-col gap-6">
        <h2 className="text-3xl sm:text-4xl font-semibold tracking-tight text-neutral-900 dark:text-white">
          Why use a browser extension framework?
        </h2>

        <p className="text-neutral-600 dark:text-neutral-400 text-lg leading-relaxed max-w-3xl">
          Browser extensions need different files, browser APIs, manifest formats,
          permissions, and build outputs than regular web apps. A{" "}

          <a href="/docs/compare" className="text-[#0e62f7] hover:opacity-80 no-underline">
            browser extension framework
          </a>

          {" "}

          removes that glue: one workflow handles Chrome, Edge, and Firefox
          extension development, manifest filtering per target, reload behavior
          tuned for service workers and content scripts, and packaging ready for
          the Chrome Web Store, addons.mozilla.org, and the Edge Add-ons store.
        </p>

        <p className="text-neutral-600 dark:text-neutral-400 text-lg leading-relaxed max-w-3xl">
          Extension.js gives you that workflow. One JavaScript or TypeScript
          project, one{" "}

          <code className="text-neutral-800 dark:text-neutral-200">
            manifest.json
          </code>

          , separate{" "}

          <code className="text-neutral-800 dark:text-neutral-200">
            dist/\<browser>
          </code>

          {" "}

          outputs, and a CLI that gets out of your way, making it effortless to
          ship a single codebase as a cross-browser extension.
        </p>
      </div>
    </div>
  </section>

  <section className="flex flex-col items-center text-center gap-8">
    <div>
      <h2 className="text-3xl sm:text-4xl font-semibold tracking-tight">
        Watch the full developer workflow
      </h2>

      <p className="text-gray-600 dark:text-gray-300 mt-3 text-lg">
        From scaffold to running extension, in one modern toolchain.
      </p>
    </div>

    <div className="w-full max-w-5xl">
      <iframe className="w-full aspect-video rounded-2xl shadow-2xl ring-1 ring-black/5" src="https://www.loom.com/embed/58e21900d693417db1e0e59c0a96c4b3?sid=80cf1003-7ed1-4f9d-a3fb-01c7876983ad" title="Extension.js developer workflow" loading="lazy" referrerPolicy="no-referrer-when-downgrade" allow="clipboard-write; encrypted-media; fullscreen" allowFullScreen />
    </div>
  </section>

  <section className="flex flex-col gap-10">
    <div className="text-center max-w-3xl mx-auto">
      <h2 className="text-3xl sm:text-4xl font-semibold tracking-tight">
        Core features for the{" "}
        <span className="text-[#0e62f7]">full extension lifecycle</span>
      </h2>

      <p className="text-gray-600 dark:text-gray-300 mt-3 text-lg">
        Build, test, and ship for every browser with one modern extension
        workflow.
      </p>
    </div>

    <div className="ext-feature-grid">
      {/* A — wide, media: engines */}

      <a href="/docs/features/cross-browser-compatibility" className="ext-feature-card ext-fa">
        <div className="flex items-center -space-x-2">
          <img src="https://media.extension.land/logos/browsers/chromium.svg" alt="Chromium" className="h-10 w-10" />

          <img src="https://media.extension.land/logos/browsers/firefox.svg" alt="Firefox" className="h-10 w-10" />
        </div>

        <div>
          <h3 className="text-lg font-semibold mb-2">
            Compile one extension into browser-specific output
          </h3>

          <p className="text-sm text-gray-600 dark:text-gray-400 leading-relaxed">
            Build once for Chrome, Edge, Firefox, and custom Chromium or Gecko
            targets. Browser-specific output stays predictable across
            development, testing, and release builds.{" "}
          </p>
        </div>
      </a>

      {/* B — narrow, media: browsers */}

      <a href="/docs/implementation-guide/manifest-json" className="ext-feature-card ext-fb">
        <div className="flex items-center -space-x-2">
          <img src="https://mintcdn.com/extensionjs/gjDFG63IAocqD1dD/images/vendor/chrome.svg?fit=max&auto=format&n=gjDFG63IAocqD1dD&q=85&s=ceae7783b27e093414f91a02abc817fa" alt="Chrome" className="h-10 w-10" width="276" height="276" data-path="images/vendor/chrome.svg" />

          <img src="https://mintcdn.com/extensionjs/3TIjz08f15ShJ-XI/images/vendor/firefox.svg?fit=max&auto=format&n=3TIjz08f15ShJ-XI&q=85&s=1625a24d1d44ff8568f45c43139e6d29" alt="Firefox" className="h-10 w-10" width="51500" height="51500" data-path="images/vendor/firefox.svg" />

          <img src="https://mintcdn.com/extensionjs/gjDFG63IAocqD1dD/images/vendor/edge.svg?fit=max&auto=format&n=gjDFG63IAocqD1dD&q=85&s=f03d86784148c780abe9be075c41057a" alt="Edge" className="h-10 w-10" width="27600" height="27600" data-path="images/vendor/edge.svg" />
        </div>

        <div>
          <h3 className="text-lg font-semibold mb-2">
            Keep extension structure explicit
          </h3>

          <p className="text-sm text-gray-600 dark:text-gray-400 leading-relaxed">
            Manifest, paths, and emitted assets stay in sync as your extension
            grows.
          </p>
        </div>
      </a>

      {/* C — narrow */}

      <a href="/docs/features/extension-configuration" className="ext-feature-card ext-fc">
        <img src="https://media.extension.land/track/extension-js.png" alt="Extension.js" className="h-10 w-10 object-contain" />

        <div>
          <h3 className="text-lg font-semibold mb-2">
            Tune behavior with config
          </h3>

          <p className="text-sm text-gray-600 dark:text-gray-400 leading-relaxed">
            Override defaults through <code>extension.config.js</code> for
            custom builds.{" "}
          </p>
        </div>
      </a>

      {/* D — wide, media: frameworks */}

      <a href="/docs/getting-started/templates" className="ext-feature-card ext-fd">
        <div className="flex items-center -space-x-2">
          <img src="https://mintcdn.com/extensionjs/3TIjz08f15ShJ-XI/images/vendor/react-original.svg?fit=max&auto=format&n=3TIjz08f15ShJ-XI&q=85&s=3b33c8ecd37f96dc4f6406a8da6d4d11" alt="React" className="h-10 w-10" width="128" height="128" data-path="images/vendor/react-original.svg" />

          <img src="https://mintcdn.com/extensionjs/3TIjz08f15ShJ-XI/images/vendor/vuejs-original.svg?fit=max&auto=format&n=3TIjz08f15ShJ-XI&q=85&s=807cafde7096ed00459532cb29922270" alt="Vue" className="h-10 w-10" width="128" height="128" data-path="images/vendor/vuejs-original.svg" />

          <img src="https://mintcdn.com/extensionjs/3TIjz08f15ShJ-XI/images/vendor/svelte-original.svg?fit=max&auto=format&n=3TIjz08f15ShJ-XI&q=85&s=7db36cf60038822ebac1809d89f5fb51" alt="Svelte" className="h-10 w-10" width="128" height="128" data-path="images/vendor/svelte-original.svg" />
        </div>

        <div>
          <h3 className="text-lg font-semibold mb-2">
            Bring your preferred stack
          </h3>

          <p className="text-sm text-gray-600 dark:text-gray-400 leading-relaxed">
            Start with React, Vue, Svelte, TypeScript, or JavaScript. Keep one
            workflow so your team picks the right UI model without changing the
            extension toolchain.{" "}
          </p>
        </div>
      </a>

      {/* E — wide, media: env */}

      <a href="/docs/features/environment-variables" className="ext-feature-card ext-fe">
        <img src="https://mintcdn.com/extensionjs/gjDFG63IAocqD1dD/images/vendor/env-vars.png?fit=max&auto=format&n=gjDFG63IAocqD1dD&q=85&s=7fd070f9e7475d4c1cc8250a8faa541a" alt="Environment variables" className="h-10 w-10 object-contain" width="225" height="225" data-path="images/vendor/env-vars.png" />

        <div>
          <h3 className="text-lg font-semibold mb-2">
            Inject environment values cleanly
          </h3>

          <p className="text-sm text-gray-600 dark:text-gray-400 leading-relaxed">
            Load environment values by browser and mode, then replace them
            across JavaScript, JSON, and HTML. Development secrets never leak
            into production bundles.{" "}
          </p>
        </div>
      </a>

      {/* F — narrow, media: stores */}

      <a href="/docs/features/multi-platform-builds" className="ext-feature-card ext-ff">
        <div className="flex items-center -space-x-2">
          <img src="https://media.extension.land/logos/stores/chrome-web-store.png" alt="Chrome Web Store" className="h-10 w-10" />

          <img src="https://media.extension.land/logos/stores/firefox-addons.png" alt="Firefox Add-ons" className="h-10 w-10" />

          <img src="https://media.extension.land/logos/stores/microsoft-edge-addons.png" alt="Microsoft Edge Add-ons" className="h-10 w-10" />
        </div>

        <div>
          <h3 className="text-lg font-semibold mb-2">
            Build, preview, package
          </h3>

          <p className="text-sm text-gray-600 dark:text-gray-400 leading-relaxed">
            One flow from local check to store-ready artifacts per browser.{" "}
          </p>
        </div>
      </a>
    </div>

    <div className="flex justify-center">
      <a href="/docs/features" className="inline-flex items-center gap-3 rounded-lg bg-[#0e62f7] px-12 py-4 text-white text-lg font-semibold hover:opacity-90 transition no-underline">
        Explore all features ⏵⏵⏵
      </a>
    </div>
  </section>

  <section className="flex flex-col gap-10">
    <div className="text-center max-w-3xl mx-auto">
      <h2 className="text-3xl sm:text-4xl font-semibold tracking-tight">
        Choose your <span className="text-[#0e62f7]">framework</span>. Keep your
        workflow.
      </h2>

      <p className="text-gray-600 dark:text-gray-300 mt-3 text-lg">
        Start with production-ready templates for React, Preact, Vue, Svelte,
        TypeScript, or JavaScript.
      </p>
    </div>

    <div className="ext-template-grid">
      <a href="/docs/languages-and-frameworks/react" className="ext-feature-card">
        <img src="https://mintcdn.com/extensionjs/3TIjz08f15ShJ-XI/images/vendor/react-original.svg?fit=max&auto=format&n=3TIjz08f15ShJ-XI&q=85&s=3b33c8ecd37f96dc4f6406a8da6d4d11" alt="React" className="h-10 w-10" width="128" height="128" data-path="images/vendor/react-original.svg" />

        <div>
          <h3 className="text-lg font-semibold mb-2">React</h3>

          <p className="text-sm text-gray-600 dark:text-gray-400 leading-relaxed">
            Component-based UI with full Manifest V3 (MV3) compatibility.
            Ready-to-ship popup, options, and content scripts.{" "}
          </p>
        </div>
      </a>

      <a href="/docs/languages-and-frameworks/preact" className="ext-feature-card">
        <img src="https://preactjs.com/branding/symbol.svg" alt="Preact" className="h-10 w-10" />

        <div>
          <h3 className="text-lg font-semibold mb-2">Preact</h3>

          <p className="text-sm text-gray-600 dark:text-gray-400 leading-relaxed">
            Same React API in a 3kB runtime. Great for content scripts where
            bundle size matters.{" "}
          </p>
        </div>
      </a>

      <a href="/docs/languages-and-frameworks/vue" className="ext-feature-card">
        <img src="https://mintcdn.com/extensionjs/3TIjz08f15ShJ-XI/images/vendor/vuejs-original.svg?fit=max&auto=format&n=3TIjz08f15ShJ-XI&q=85&s=807cafde7096ed00459532cb29922270" alt="Vue" className="h-10 w-10" width="128" height="128" data-path="images/vendor/vuejs-original.svg" />

        <div>
          <h3 className="text-lg font-semibold mb-2">Vue</h3>

          <p className="text-sm text-gray-600 dark:text-gray-400 leading-relaxed">
            Progressive framework with single-file components, wired up for
            extension contexts out of the box.{" "}
          </p>
        </div>
      </a>

      <a href="/docs/languages-and-frameworks/svelte" className="ext-feature-card">
        <img src="https://mintcdn.com/extensionjs/3TIjz08f15ShJ-XI/images/vendor/svelte-original.svg?fit=max&auto=format&n=3TIjz08f15ShJ-XI&q=85&s=7db36cf60038822ebac1809d89f5fb51" alt="Svelte" className="h-10 w-10" width="128" height="128" data-path="images/vendor/svelte-original.svg" />

        <div>
          <h3 className="text-lg font-semibold mb-2">Svelte</h3>

          <p className="text-sm text-gray-600 dark:text-gray-400 leading-relaxed">
            Compile-time UI with smaller runtime. Ideal when every kilobyte in a
            content script counts.{" "}
          </p>
        </div>
      </a>

      <a href="/docs/languages-and-frameworks/typescript" className="ext-feature-card">
        <img src="https://mintcdn.com/extensionjs/3TIjz08f15ShJ-XI/images/vendor/typescript-original.svg?fit=max&auto=format&n=3TIjz08f15ShJ-XI&q=85&s=b7720020aa3a4079b38ccbf8c2f56f5c" alt="TypeScript" className="h-10 w-10" width="128" height="128" data-path="images/vendor/typescript-original.svg" />

        <div>
          <h3 className="text-lg font-semibold mb-2">TypeScript</h3>

          <p className="text-sm text-gray-600 dark:text-gray-400 leading-relaxed">
            Static types for popup, content, and background scripts. Catch
            manifest and messaging bugs at compile time.{" "}
          </p>
        </div>
      </a>

      <a href="/docs/languages-and-frameworks/ecmascript-modules" className="ext-feature-card">
        <img src="https://mintcdn.com/extensionjs/3TIjz08f15ShJ-XI/images/vendor/javascript-original.svg?fit=max&auto=format&n=3TIjz08f15ShJ-XI&q=85&s=c523de36b8f066538f936fc6b3329dc8" alt="JavaScript" className="h-10 w-10" width="128" height="128" data-path="images/vendor/javascript-original.svg" />

        <div>
          <h3 className="text-lg font-semibold mb-2">JavaScript</h3>

          <p className="text-sm text-gray-600 dark:text-gray-400 leading-relaxed">
            Plain ES modules, no compile step required. Start fast and add
            tooling when you need it.{" "}
          </p>
        </div>
      </a>
    </div>

    <div className="flex justify-center">
      <a href="/docs/getting-started/templates" className="inline-flex items-center gap-3 rounded-lg bg-[#0e62f7] px-12 py-4 text-white text-lg font-semibold hover:opacity-90 transition no-underline">
        Browse templates ⏵⏵⏵
      </a>
    </div>
  </section>

  <section className="w-full">
    <div className="ext-migrate-callout">
      <div>
        <h2 className="text-2xl sm:text-3xl font-semibold tracking-tight">
          Coming from another framework?
        </h2>

        <p className="text-gray-600 dark:text-gray-400 mt-3 text-base sm:text-lg max-w-2xl">
          Most React, Vue, and Svelte source files copy across without rewriting.
          The work is replacing the bundler config and moving generated manifests
          back to a real manifest.json.
        </p>
      </div>

      <div className="ext-migrate-actions">
        <a href="/docs/compare/extension-js-vs-wxt" className="ext-migrate-btn">
          Compare frameworks ⏵
        </a>

        <a href="/docs/migrate/from-crxjs" className="ext-migrate-btn">
          Migrate your extension ⏵
        </a>
      </div>
    </div>
  </section>

  <section className="flex flex-col items-center text-center gap-6">
    <div>
      <h2 className="text-3xl sm:text-4xl font-semibold tracking-tight">
        Backing the open-source core
      </h2>

      <p className="text-gray-600 dark:text-gray-300 mt-3 text-lg max-w-2xl">
        Sponsors help the project ship faster releases, better developer
        experience (DX), and long-term reliability for extension teams.
      </p>
    </div>

    <div className="ext-sponsors">
      <a href="https://extension.dev/?utm_medium=sponsor&utm_source=extensionjs" rel="noreferrer" target="_blank" className="ext-sponsor-tile" aria-label="extension.dev">
        <img alt="extension.dev" src="https://mintcdn.com/extensionjs/rnXP2INmBiIBB-KO/images/sponsors/extensiondev.svg?fit=max&auto=format&n=rnXP2INmBiIBB-KO&q=85&s=6cc08ea65bd172be4266eba5274763ae" loading="lazy" className="ext-sponsor-logo block dark:hidden" width="1001" height="155" data-path="images/sponsors/extensiondev.svg" />

        <img alt="extension.dev" src="https://mintcdn.com/extensionjs/rnXP2INmBiIBB-KO/images/sponsors/extensiondev_dark.svg?fit=max&auto=format&n=rnXP2INmBiIBB-KO&q=85&s=f283f9391426d7c18be3d05622edebce" loading="lazy" className="ext-sponsor-logo hidden dark:block" width="1001" height="155" data-path="images/sponsors/extensiondev_dark.svg" />
      </a>

      <a href="https://mintlify.com/?utm_medium=sponsor&utm_source=extensionjs" rel="noreferrer" target="_blank" className="ext-sponsor-tile" aria-label="Mintlify">
        <img alt="Mintlify" src="https://mintcdn.com/extensionjs/rnXP2INmBiIBB-KO/images/sponsors/mintlify.svg?fit=max&auto=format&n=rnXP2INmBiIBB-KO&q=85&s=40a4945c26268666007edf9a2b888e9f" loading="lazy" className="ext-sponsor-logo block dark:hidden" width="1682" height="368" data-path="images/sponsors/mintlify.svg" />

        <img alt="Mintlify" src="https://mintcdn.com/extensionjs/rnXP2INmBiIBB-KO/images/sponsors/mintlify_dark.svg?fit=max&auto=format&n=rnXP2INmBiIBB-KO&q=85&s=c6d2c0cb1723d06e312a64180da9b62d" loading="lazy" className="ext-sponsor-logo hidden dark:block" width="1682" height="368" data-path="images/sponsors/mintlify_dark.svg" />
      </a>
    </div>

    <a href="https://github.com/sponsors/extension-js" target="_blank" rel="noreferrer" className="text-sm text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200">
      Become a sponsor ⏵
    </a>
  </section>

  <section className="flex flex-col gap-8 max-w-3xl mx-auto w-full">
    <div className="text-center">
      <h2 className="text-3xl sm:text-4xl font-semibold tracking-tight">
        Frequently asked questions
      </h2>
    </div>

    <AccordionGroup>
      <Accordion title="What is a browser extension?">
        A browser extension is software that adds features to Chrome, Firefox,
        Edge, or another browser. Extensions inject UI, react to browser events,
        and call privileged APIs the page itself cannot. See [What is a browser
        extension?](/docs/concepts/what-is-a-browser-extension) for the full
        primer.
      </Accordion>

      <Accordion title="Is Extension.js a Chrome extension framework?">
        Yes. Extension.js works as a Chrome extension framework, and also as a
        Firefox and Edge extension framework, from the same project. Pick a
        target with `--browser=chrome`, `--browser=firefox`, or
        `--browser=edge`. See [Browsers
        available](/docs/browsers/browsers-available).
      </Accordion>

      <Accordion title="How does Extension.js handle hot module replacement during development?">
        Run `npx extension dev` and the CLI watches your project for changes.
        Edits to popups, content scripts, service workers, and options pages
        trigger the fastest safe update path. The CLI uses hot module
        replacement (HMR) when supported and targeted reloads otherwise. It
        automatically resolves common pain points like stale service workers and
        missed content-script updates.
      </Accordion>

      <Accordion title="How do I build one extension for Chrome, Edge, and Firefox?">
        Extension.js compiles a single codebase into browser-specific output.
        One set of commands produces correctly packaged builds for Chrome, Edge,
        Firefox, and other Chromium-based browsers. Each build gets the right
        manifest format, paths, and platform adjustments. Your continuous
        integration (CI) pipeline uses the same build step with different
        browser flags. This reduces drift between store submissions.
      </Accordion>

      <Accordion title="Can I use React, Preact, Vue, Svelte, or TypeScript?">
        Yes. Extension.js ships production-ready templates for React, Preact,
        Vue, Svelte, TypeScript, and plain JavaScript. You write components the
        same way you would in any frontend project. Framework choice does not
        affect the core workflow.
      </Accordion>

      <Accordion title="Does Extension.js support Manifest V3?">
        Yes. The toolchain is built around Manifest V3 and the constraints
        browser stores enforce today: service workers, declarative APIs, updated
        permissions, and stricter packaging. Manifest V3 (MV3) is the default,
        not an afterthought. For common pitfalls, see [Manifest V3
        troubleshooting](/docs/concepts/manifest-v3).
      </Accordion>

      <Accordion title="How do I troubleshoot Manifest V3 service worker and permissions issues?">
        Most Manifest V3 troubleshooting falls into a few buckets: service
        worker registration and `type: "module"`, the new
        `web_accessible_resources` shape, the split between `permissions` and
        `host_permissions`, and `declarative_net_request` differences in
        Firefox. See [Manifest V3 troubleshooting](/docs/concepts/manifest-v3)
        for the fixes.
      </Accordion>

      <Accordion title="How do I migrate from a custom webpack or Vite setup?">
        Extension.js replaces the extension-specific glue in hand-rolled bundler
        configs. It handles manifest versioning, multi-browser output,
        content-script injection, and reload orchestration. Move your source
        files and manifest into an Extension.js project and the CLI handles the
        rest. Your React/Vue/Svelte/TS code works without rewriting.
      </Accordion>

      <Accordion title="Does Extension.js work with monorepos and environment variables?">
        Extension.js supports pnpm, npm, and Yarn workspaces. Path resolution
        and shared dependencies work across workspace boundaries. Extension.js
        injects environment variables per browser and build mode, replacing
        values across JS, JSON, and HTML. Development secrets never leak into
        production bundles.
      </Accordion>

      <Accordion title="Is Extension.js free to use?">
        Yes. Extension.js is open source under the
        [MIT license](https://github.com/extension-js/extension.js/blob/main/LICENSE).
        There is no paid tier, usage cap, or telemetry-required mode. The
        framework is funded by sponsors and contributors. Review the
        [telemetry contract](/docs/features/telemetry-and-privacy) for the
        exact data shape.
      </Accordion>

      <Accordion title="Does Extension.js support Safari?">
        Not yet. `--browser=safari` is not a CLI target today. You can still
        author Safari extensions with shared web code and add Safari-specific
        build steps outside this workflow. See [Browsers
        available](/docs/browsers/browsers-available#safari-and-other-webkit-targets)
        for the current scope.
      </Accordion>

      <Accordion title="What does Extension.js add to my bundle?">
        Production builds (`extension build`) emit only the code your
        extension references plus a small reload runtime that is removed in
        production. Dev builds include extra HMR and reload glue. Output sits
        under `dist/<browser>` so you can compare sizes between browsers.
        Content-script bundles stay close to what your source plus your
        chosen UI framework would produce.
      </Accordion>

      <Accordion title="How do I migrate from another framework?">
        Most React, Vue, and Svelte source files copy across without
        rewriting. The work is in three places: replacing the bundler config,
        moving generated manifests back to a hand-authored `manifest.json`
        with [browser-prefixed
        keys](/docs/features/browser-specific-fields), and updating
        `package.json` scripts. See [Migrate from
        CRXJS](/docs/migrate/from-crxjs) for the step-by-step.
      </Accordion>
    </AccordionGroup>
  </section>

  <div className="ext-footer">
    <div className="ext-footer-inner">
      <div className="ext-footer-cmd">
        <code>npx extension\@latest create my-extension</code>
      </div>

      <div className="ext-footer-right">
        <ul className="ext-footer-links">
          <li>
            <a href="https://github.com/extension-js/extension.js/blob/main/CODE_OF_CONDUCT.md" target="_blank" rel="noreferrer">
              Code of Conduct{" "}

              <Icon icon="arrow-up-right-from-square" size={10} />
            </a>
          </li>

          <li>
            <a href="https://github.com/extension-js/extension.js/releases" target="_blank" rel="noreferrer">
              Changelog <Icon icon="arrow-up-right-from-square" size={10} />
            </a>
          </li>

          <li>
            <a href="https://github.com/extension-js/extension.js/security" target="_blank" rel="noreferrer">
              Security <Icon icon="arrow-up-right-from-square" size={10} />
            </a>
          </li>
        </ul>

        <p className="ext-footer-copy">
          MIT (c) Cezar Augusto and the{" "}
          <a href="/docs/hall-of-fame">Extension.js authors</a>.
        </p>
      </div>
    </div>
  </div>
</div>
