Manifest V3 in practice: what actually changed for Chrome extensions

Manifest V3 has been the default since Chrome phased out V2, and a lot of 2021-era tutorial code silently breaks against it. Having shipped a dozen client extensions on MV3 — scrapers, outreach automators, data capture tools — here's the honest cheat sheet of what changed and how to design for it.

1. Background pages are gone — long live service workers

The persistent background page is replaced by a service worker that can be killed at any moment. Any state you keep in a global variable is a bug waiting to happen.

// ❌ breaks after the worker sleeps
let queue = [];
chrome.runtime.onMessage.addListener((msg) => queue.push(msg));

// ✅ survives sleep — state lives in storage
chrome.runtime.onMessage.addListener((msg) =>
  chrome.storage.session.append(msg) // or your own queue in chrome.storage.local
);

Design rule: the service worker is a router, not a brain. Persist state, react to events, get out.

2. Remote code is banned

You can no longer eval, new Function(), or load scripts from your server into the extension context. Everything ships inside the package. Practical consequences:

  • Bundle your dependencies at build time (Vite/esbuild works great).
  • Config-driven behaviour is fine — fetch a JSON file and branch on it, just don't fetch and execute code.
  • Heavy templates? Ship them as assets and render them into the page, not the other way around.

3. <script> injection into pages is restricted

MV3 content scripts live in an isolated world. To run code in the page's own context (reading page-set variables, hooking fetch), inject a script file from your bundle via the world: 'MAIN' option — inline strings won't fly:

chrome.scripting.executeScript({
  target: { tabId },
  world: 'MAIN',
  files: ['page-hook.js']
});

4. Permissions got scarier — and more honest

Chrome reviews extensions with broad <all_urls> host permissions hard. The pattern I use for client tools:

  • Use activeTab + scripting wherever the action is user-initiated — this alone passes review for most internal tools.
  • Request broad hosts only when the extension truly needs background monitoring, and expect a review period measured in days, not hours.
  • Private distribution via the Chrome Web Store (unlisted) keeps a team-only tool out of public search while staying auto-updated.

What this means for business extensions

The teams I build for care about one thing: does it work every morning. MV3's sleeping worker means you design like a backend engineer — events in, storage as source of truth, alarms (chrome.alarms) for anything periodic. Do that and MV3 is not a limitation; it's free reliability.

Hiring? I build Manifest V3 extensions end-to-end — from scoping to private Web Store publication.