← Back to blog
Deep Dive · 10 min read

Manifest V3 Explained: What Every Chrome Extension Builder Should Know

Manifest V3 is the modern Chrome extension standard. Here's what changed, why it matters, and how AI builders handle it for you.

Illustration for the ManifestGo article: Manifest V3 Explained: What Every Chrome Extension Builder Should Know

Manifest V3 is now the default — and only — supported manifest version for new Chrome extensions in the Chrome Web Store. If you're creating Chrome extensions today, you're creating MV3 extensions, whether you write them by hand or generate them with AI.

What changed from Manifest V2

  • Background pages were replaced by service workers — short-lived, event-driven, no DOM access.
  • Remotely hosted code is banned. All JavaScript must ship inside the extension package.
  • The webRequest blocking API was replaced with declarativeNetRequest for content blockers.
  • Stricter content security policies on extension pages.

Why MV3 is harder to write by hand

Service workers introduce a different mental model — you can't keep long-lived state in memory, you have to use chrome.storage or alarms, and you need to handle wake-ups gracefully. AI generators encode these patterns so you don't have to relearn them.

How ManifestGo handles MV3 by default

Every extension ManifestGo generates ships as Manifest V3 with a properly-scoped service worker, declarative permissions, and a content security policy that passes Chrome Web Store review out of the box.

The declarativeNetRequest rule limits that trip up migrations

declarativeNetRequest replaced blocking webRequest for content blockers, but it comes with hard caps: 30,000 static rules per extension by default (up to 330,000 for extensions using the guaranteed-minimum tiers Chrome grants automatically), 5,000 dynamic rules registered at runtime, and 50 static ruleset files, of which only 50 can be enabled at once. Rules also can't inspect request bodies — only URLs, headers, and resource types — which is why some MV2 ad-blocking logic couldn't be ported 1:1.

Exact permission and CSP fields Chrome checks

  • content_security_policy must be an object with an extension_pages key in MV3, not a bare string like MV2 used.
  • 'unsafe-eval' and remotely hosted scripts are rejected outright — Chrome parses your CSP and flags disallowed sources during upload review.
  • web_accessible_resources is now an array of objects, each requiring a matches field, so 'any page can load my resource' must be explicitly scoped per origin.
  • The optional_host_permissions field lets you request extra sites at runtime via chrome.permissions.request instead of listing them all upfront.

The chrome.action API replaces browserAction and pageAction

MV2's separate browserAction and pageAction APIs were merged into a single chrome.action namespace. Methods like chrome.action.setBadgeText, chrome.action.setIcon, and chrome.action.setPopup work the same conceptually, but any tutorial or Stack Overflow snippet referencing chrome.browserAction will throw 'chrome.browserAction is undefined' in an MV3 service worker.

Debugging a service worker that keeps saying 'inactive'

  1. Confirm the file path in background.service_worker matches exactly, including case — Linux-hosted Chrome builds are case-sensitive even if your OS isn't.
  2. Check for a top-level await or blocking synchronous loop — either prevents the worker from finishing registration.
  3. Verify you're not importing a non-module script without setting "type": "module" in the background key.
  4. Use chrome.runtime.getManifest() in the service worker console to confirm Chrome parsed the fields you expect.
A service worker listed as 'inactive' in chrome://extensions isn't broken — it's asleep. It wakes on the next matching event; only a load-time error keeps it truly dead.

What's still evolving post-MV3 in 2026

Chrome has continued adjusting MV3 details after the 2024 MV2 phase-out: expanded declarativeNetRequest rule quotas for well-behaved extensions, the userScripts API returning in a more restricted form for developer-mode-gated script injection, and ongoing refinements to the Enterprise policy ExtensionManifestV2Availability, which some organizations used to delay migration. None of this brings back arbitrary remote code execution or persistent background pages.

Frequently asked questions

Can I still use setTimeout for long delays inside an MV3 service worker?

You can, but the worker may be terminated before a long setTimeout fires because it only survives roughly 30 seconds of inactivity; use chrome.alarms for anything longer than that, since alarms wake the worker even after it unloads.

What does 'This extension may soon be unsupported' mean in chrome://extensions?

That warning appears on Manifest V2 extensions still installed after Chrome's MV2 sunset; Chrome will eventually disable them entirely, so the fix is migrating to a Manifest V3 build.

Does Manifest V3 block all forms of dynamic code execution?

It blocks remotely fetched and eval'd code, but chrome.scripting.executeScript can still inject a function object defined locally in your extension, which covers most legitimate dynamic-injection use cases.

Keep reading