Manifest V3 + GitHub Actions CI/CD + Chrome & Firefox deploy.
Build your extension. Push to deploy.
English | 한국어
Part of Starter Series — Stop explaining CI/CD to your AI every time. Clone and start.
Docker Deploy · Discord Bot · Telegram Bot · Browser Extension · Electron App · npm Package · React Native · VS Code Extension · MCP Server · Python MCP Server · Cloudflare Pages
# 1. Click "Use this template" on GitHub (or clone)
git clone https://github.com/starter-series/browser-extension-starter.git my-extension
cd my-extension
# 2. Install dependencies
npm install
# 3. Load in Chrome
# → chrome://extensions → Enable Developer Mode → Load unpacked → select project root
# 4. Build zip for store
npm run build:chrome├── manifest.json # MV3 manifest (Chrome + Firefox)
├── src/
│ ├── popup/ # Extension popup (HTML + JS)
│ ├── options/ # Options page (HTML + JS)
│ ├── background/ # Service worker
│ └── content/ # Content script (JS + CSS)
├── assets/icons/ # Extension icons (16/32/48/128)
├── .github/
│ ├── workflows/
│ │ ├── ci.yml # Validate, audit, lint, test, build
│ │ ├── cd.yml # Deploy to Chrome Web Store
│ │ ├── cd-firefox.yml # Deploy to Firefox Add-ons
│ │ └── setup.yml # Auto setup checklist on first use
│ └── PULL_REQUEST_TEMPLATE.md
├── docs/
│ ├── CWS_SETUP.md # Chrome Web Store publishing guide
│ ├── AMO_SETUP.md # Firefox Add-ons publishing guide
│ └── PRIVACY_POLICY_TEMPLATE.md # Privacy policy template for store
└── package.json
- Manifest V3 — Chrome + Firefox cross-browser support
- CI Pipeline — Manifest validation, permission audit, security audit, lint, test, build verification
- CD Pipeline — One-click deploy to Chrome Web Store or Firefox Add-ons + auto GitHub Release
- Version management —
npm run version:patch/minor/majorto bumpmanifest.json - Security — CI warns on risky permissions, broad host access, and dependency vulnerabilities
- Dev mode —
npm run devfor live-reload withweb-ext - Starter code — Popup with toggle + options page + background + content script
- Store-ready — OAuth setup guide + privacy policy template
- Template setup — Auto-creates setup checklist issue on first use
| Step | What it does |
|---|---|
| Validate manifest | Checks manifest.json is valid JSON with required fields + version format |
| Audit permissions | Warns on risky permissions and broad host access |
| Security audit | npm audit for dependency vulnerabilities |
| Lint | ESLint (JS) + Stylelint (CSS) |
| Test | Jest (passes with no tests by default) |
| Build verification | Builds zip and checks size stays under 10 MB |
| Workflow | What it does |
|---|---|
CodeQL (codeql.yml) |
Static analysis for security vulnerabilities (push/PR + weekly) |
Maintenance (maintenance.yml) |
Weekly CI health check — auto-creates issue on failure |
Stale (stale.yml) |
Labels inactive issues/PRs after 30 days, auto-closes after 7 more |
| Step | What it does |
|---|---|
| Version guard | Fails if git tag already exists for this version |
| Build | Zips manifest + src + assets |
| Upload | Publishes to Chrome Web Store via API |
| GitHub Release | Creates a tagged release with zip attached |
| Artifact | Saves zip as GitHub Actions artifact |
How to deploy:
- Set up GitHub Secrets (see below)
- Bump version:
npm run version:patch(orversion:minor/version:major) - Go to Actions tab → Deploy to Chrome Web Store → Run workflow
- Choose publish target (
defaultortrustedTesters) → Run
| Secret | Description |
|---|---|
CWS_EXTENSION_ID |
Your Chrome Web Store extension ID |
CWS_CLIENT_ID |
Google OAuth2 client ID |
CWS_CLIENT_SECRET |
Google OAuth2 client secret |
CWS_REFRESH_TOKEN |
Google OAuth2 refresh token |
See docs/CWS_SETUP.md for a detailed setup guide.
| Secret | Description |
|---|---|
AMO_JWT_ISSUER |
AMO API key (JWT issuer) |
AMO_JWT_SECRET |
AMO API secret |
See docs/AMO_SETUP.md for a detailed setup guide.
# Live-reload in Chromium
npm run dev
# Bump version (updates manifest.json)
npm run version:patch # 1.0.0 → 1.0.1
npm run version:minor # 1.0.0 → 1.1.0
npm run version:major # 1.0.0 → 2.0.0
# Build store zip
npm run build:chrome
# Lint & test
npm run lint # JS
npm run lint:css # CSS
npm test- Edit
manifest.json— name, description, permissions, match patterns - Replace icons in
assets/icons/ - Build your popup in
src/popup/ - Configure settings in
src/options/ - Add background logic in
src/background/ - Add page injection in
src/content/ - Copy
docs/PRIVACY_POLICY_TEMPLATE.mdand fill in your details
Note: The default content script matches
https://*/*andhttp://*/*. If your extension only needs specific sites, narrow thematchesinmanifest.jsonto minimize permissions — Chrome Web Store review is stricter with broad host permissions.
WXT and Plasmo are excellent frameworks that abstract away browser extension internals. This template takes a fundamentally different approach:
| This template | WXT / Plasmo | |
|---|---|---|
| Philosophy | Thin starter with CI/CD | Full framework with runtime |
| Build system | None (raw files) | Vite / Parcel (required) |
| Learning curve | Read the browser APIs directly | Learn the framework's abstractions |
| CI/CD | Full pipeline included | Not included |
| Dependencies | 7 dev, 0 runtime | 100+ |
| AI/vibe-coding | LLMs generate clean vanilla JS | LLMs must understand framework conventions |
| Best for | Utility extensions, scripts, simple tools | Complex apps with multi-page UIs |
Choose this template if:
- You want to understand what your extension actually does, line by line
- You need production CI/CD out of the box (no other template provides this)
- You're using AI tools to generate extension code — vanilla JS produces the cleanest AI output
- Your extension is a utility, not a full application
Choose WXT/Plasmo if:
- You need React/Vue/Svelte components in your extension UI
- You want file-based routing and auto-imports
- Your extension has complex multi-page architecture
This template intentionally uses vanilla JavaScript to keep the zero-build-step philosophy. If you need TypeScript:
- Add
typescriptto devDependencies - Add a
tsconfig.json - Add a
tscbuild step topackage.json - Rename
.jsfiles to.ts
This keeps TypeScript opt-in rather than forcing a build pipeline on everyone. For many extensions (content scripts, simple popups, background listeners), vanilla JS is all you need.
PRs welcome. Please use the PR template.