Skip to main content

Installation

This guide covers adding CRXJS Vite Plugin to an existing Vite project or setting up a new project from scratch.
Want to get started quickly? Use npm create crxjs@latest to scaffold a new project. See the Quick start guide.

Prerequisites

Before installing CRXJS, ensure you have:
  • Node.js 14.18+ or 16+
  • A Vite project (or create one using npm create vite@latest)

Install the plugin

Install @crxjs/vite-plugin as a dev dependency:
npm install --save-dev @crxjs/vite-plugin

Create a manifest

Create a manifest.json file in your project root. This file defines your extension’s metadata and entry points:
manifest.json
{
  "manifest_version": 3,
  "name": "My Chrome Extension",
  "version": "1.0.0",
  "action": {
    "default_popup": "index.html"
  }
}
CRXJS supports Manifest V3, the latest version of the Chrome Extension manifest format with enhanced security features.

Manifest examples

Here are some common manifest configurations:
{
  "manifest_version": 3,
  "name": "My Extension",
  "version": "1.0.0",
  "action": {
    "default_popup": "index.html"
  }
}
All paths in the manifest are relative to your Vite project root (where vite.config.js is located). Use paths that start with a letter, not ./ or /.

Update Vite config

Import and configure the CRXJS plugin in your vite.config.js or vite.config.ts:
import { defineConfig } from 'vite'
import { crx } from '@crxjs/vite-plugin'
import manifest from './manifest.json'

export default defineConfig({
  plugins: [
    crx({ manifest }),
  ],
})
Ensure your package.json has "type": "module" set. Vite requires this to process your config file.

TypeScript manifest (optional)

For better type safety and dynamic configuration, use a TypeScript manifest with the defineManifest helper:
1

Create a manifest config file

Create manifest.config.ts in your project root:
manifest.config.ts
import { defineManifest } from '@crxjs/vite-plugin'
import packageJson from './package.json'

export default defineManifest({
  manifest_version: 3,
  name: packageJson.name,
  version: packageJson.version,
  action: {
    default_popup: 'index.html',
  },
})
2

Update your Vite config

Import the TypeScript manifest instead of JSON:
vite.config.ts
import { defineConfig } from 'vite'
import { crx } from '@crxjs/vite-plugin'
import manifest from './manifest.config'

export default defineConfig({
  plugins: [
    crx({ manifest }),
  ],
})
The defineManifest helper provides autocompletion and supports async functions for dynamic manifest generation.

Dynamic manifest example

You can use environment variables and dynamic logic in your TypeScript manifest:
manifest.config.ts
import { defineManifest } from '@crxjs/vite-plugin'
import packageJson from './package.json'

const { version } = packageJson

// Convert Semver to Chrome extension version format
const [major, minor, patch] = version.split('.')

export default defineManifest(async (env) => ({
  manifest_version: 3,
  name: env.mode === 'production' 
    ? 'My Extension' 
    : '[DEV] My Extension',
  version: `${major}.${minor}.${patch}`,
  version_name: version,
  action: {
    default_popup: 'index.html',
  },
}))

Run the development server

Start Vite’s development server:
npm run dev
CRXJS will:
  • Parse your manifest
  • Build all entry files (HTML pages, scripts, etc.)
  • Generate the dist folder with your extension
  • Watch for changes and rebuild automatically

Load the extension

1

Open Chrome extensions page

Navigate to chrome://extensions in Chrome or Edge
2

Enable developer mode

Toggle the “Developer mode” switch in the top right (Chrome) or left sidebar (Edge)
3

Load your extension

Drag your dist folder into the Extensions DashboardYour extension is now installed and ready to use!

Verify installation

Your extension should appear in the extensions list with:
  • The name from your manifest
  • An icon showing the first letter of your extension name (or your custom icon if specified)
  • A toggle to enable/disable it
Click the extension icon in your browser toolbar to test it. If you configured a popup page, it should open and display your Vite-powered UI.

Next steps

Quick start tutorial

Follow the 90-second tutorial to experience HMR

Manifest concepts

Learn more about manifest configuration

Add content scripts

Inject scripts into web pages

Configuration options

Explore advanced plugin configuration

Troubleshooting

”type”: “module” error

If Vite can’t process your config file, ensure your package.json includes:
package.json
{
  "type": "module"
}

Manifest paths not resolving

Manifest paths should be relative to your Vite project root and should NOT start with ./ or /:
{
  "action": {
    "default_popup": "index.html"
  },
  "background": {
    "service_worker": "src/background.js"
  }
}

Extension not loading

If your extension doesn’t load in Chrome:
  1. Check the browser console for errors
  2. Verify your dist folder was generated
  3. Ensure your manifest has at minimum: manifest_version, name, and version
  4. Try removing and re-adding the extension

Build docs developers (and LLMs) love