Back

Chrome Extension Manifest V3 Explained

Chrome Extension Manifest V3 Explained

If you’ve searched for Chrome extension tutorials recently, you’ve probably noticed something frustrating: half the guides you find reference a background page architecture that no longer works. Manifest V2 is deprecated and disabled by default in Chrome. Manifest V3 is the current platform, and understanding its architecture is the only practical starting point for extension development in 2026.

This article explains what changed, why it changed, and how the key APIs fit together.

Key Takeaways

  • Manifest V2 is deprecated; Manifest V3 is the only practical supported path for new Chrome extensions.
  • Persistent background pages are replaced by event-driven service workers, which have no DOM access and should not rely on in-memory state persisting between events.
  • The declarativeNetRequest API replaces blocking webRequest, shifting network filtering from extension code to native rule evaluation.
  • All extension JavaScript must be bundled in the package — remotely hosted code is prohibited.
  • The unified chrome.action API and the Offscreen API fill the gaps left by MV2’s browserAction, pageAction, and persistent background page.

Why Chrome Moved Away from Manifest V2

Manifest V2 extensions could run a persistent background page — a full HTML document that stayed loaded in memory indefinitely, even when the extension was doing nothing. This was convenient for developers but expensive for users. Every installed extension with a background page consumed memory and CPU continuously.

Beyond performance, MV2 allowed extensions to load and execute JavaScript from remote URLs. That meant an extension could pass Chrome Web Store review with benign code, then silently swap in malicious logic from an external server later. There was no practical way to audit what an extension was actually running.

These two problems — resource waste and unauditable remote code — are the real drivers behind Manifest V3.

The Core Architectural Changes in Chrome Extension Manifest V3

Extension Service Workers Replace Background Pages

In MV3, the persistent background page is gone. Its replacement is an extension service worker — an event-driven script that Chrome spins up when needed and terminates when idle.

This is the change that trips up most developers coming from MV2. A service worker has no DOM access and does not stay alive between events. You cannot store state in a global variable and expect it to persist. Instead, use chrome.storage for anything that needs to survive across events, and use the chrome.alarms API to schedule recurring work that previously would have lived in a setInterval call inside a background page.

{
  "background": {
    "service_worker": "background.js",
    "type": "module"
  }
}

declarativeNetRequest Replaces Blocking webRequest

MV2’s webRequest API let extensions intercept every network request and decide synchronously whether to block or modify it. This gave extensions broad visibility into all browser traffic — a significant privacy exposure — and introduced latency because every request had to wait for the extension’s response.

The declarativeNetRequest API (DNR) works differently. You define a set of rules in JSON, Chrome evaluates them natively, and extensions no longer need to synchronously intercept requests in JavaScript to block or modify them. This is faster and more private by design.

Since Chrome 120, the rule limits have expanded considerably from the early MV3 days. Content blockers like uBlock Origin Lite have shipped MV3-compatible versions, so the claim that MV3 “killed ad blockers” is not entirely accurate — though the filtering model is genuinely more restrictive than MV2-era approaches, and the original uBlock Origin remains MV2-only by its author’s choice.

No More Remotely Hosted Code

All JavaScript executed by an MV3 extension must be bundled inside the extension package itself. Loading executable code from an external CDN or API is not permitted. This makes every extension fully auditable at review time.

chrome.action API and the Offscreen API

The browserAction and pageAction APIs from MV2 are unified into the single chrome.action API in MV3. It handles the toolbar icon, badge text, and popup in one consistent interface.

For cases where you need DOM access or audio playback from a background context — things a service worker cannot do — MV3 provides the Offscreen API. It lets you create a minimal, hidden document specifically for those tasks, without the overhead of a full persistent background page. According to Can I Use, related offscreen APIs are now broadly supported in modern Chromium-based browsers.

What a Minimal MV3 Manifest Looks Like

{
  "manifest_version": 3,
  "name": "My Extension",
  "version": "1.0",
  "background": { "service_worker": "background.js" },
  "action": { "default_popup": "popup.html" },
  "permissions": ["storage", "activeTab"],
  "host_permissions": ["https://example.com/*"]
}

Notice that host permissions are now declared separately from API permissions — a deliberate change that gives users clearer visibility into what sites an extension can access.

Conclusion

Manifest V3 is a more constrained platform than MV2, and some of those constraints require real architectural changes. But the constraints exist for concrete reasons: less memory consumption, no unauditable remote code, and less exposure of raw network traffic to extension processes. If you’re starting a new extension today, MV3 is the only practical supported path. Understanding the service worker lifecycle and the declarativeNetRequest model is where that work begins.

FAQs

You should not rely on keeping state alive in memory. Service workers terminate when idle, so any in-memory state may be lost. Persist anything important to chrome.storage.local or chrome.storage.session, and read it back when the worker wakes up for the next event. Treat each event handler as if the worker were starting fresh.

No. The Chrome team provides migration documentation, but the architectural shifts — service workers replacing background pages, declarativeNetRequest replacing blocking webRequest, no remote code — usually require manual rewrites. Extensions that only used simple APIs migrate quickly, while those relying on persistent state or network interception need significant restructuring.

Yes. Alongside static rules declared in the manifest, you can add, remove, and update dynamic and session-scoped rules at runtime through chrome.declarativeNetRequest.updateDynamicRules and updateSessionRules. Chrome has expanded the available rule quotas significantly since the early MV3 releases, making the API practical for many modern filtering scenarios, including user-configurable block lists.

Use a content script when you need to interact with a specific web page's DOM. Use the Offscreen API when you need DOM-dependent capabilities — such as parsing HTML, playing audio, or using the Clipboard API — without any associated tab. The offscreen document runs in the extension's own context, not in a page.

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay