Extension Development
Browser Extension Development: A Manifest V3 Guide
Published: 2026-07-14 • 9 min read

Most extensions do not need a custom browser or an embedded engine. They need a well-built extension, and since Manifest V3 became the baseline across Chromium-based browsers, that means designing around a background model and a permissions model that behave differently from what many teams are used to from Manifest V2.
What actually changed in Manifest V3
Manifest V3 is not a cosmetic version bump. It changes three things that most extensions touch directly: how background logic runs, how network requests can be inspected or blocked, and how remote code is allowed to execute inside the extension.
| Area | Manifest V2 | Manifest V3 |
|---|---|---|
| Background logic | Persistent background page, kept alive continuously | Event-driven service worker, terminated when idle |
| Network blocking | Blocking webRequest, arbitrary code per request | declarativeNetRequest, a bounded rules engine |
| Remote code | Commonly allowed, including remotely hosted scripts | Generally disallowed; code must ship inside the package |
| Host permissions | Requested up front, broadly, in the manifest | Can be requested at runtime, narrowed to what is needed |
| Content scripts | Registered in the manifest or injected dynamically | Similar, plus a dedicated scripting API for dynamic injection |
None of these changes are arbitrary. Each closes a specific class of problem: background pages that held memory indefinitely, request-blocking code that could see and alter every byte of traffic, and remotely hosted code that could change behavior after an extension had already passed review.
Designing around the service worker lifecycle
The most common Manifest V3 migration bug is code that assumes the background context stays alive. A service worker is started for an event, and the browser is free to shut it down once it goes idle, often within seconds. Anything held only in a variable is gone when that happens.
Event wakes the worker
A browser action click, alarm, message or network event starts the service worker if it is not already running.
Worker reloads its state
On startup, the worker reads whatever it needs from chrome.storage or IndexedDB rather than assuming in-memory state survived.
Work runs to completion
Asynchronous work is kept inside the event lifetime where possible, using chrome.alarms instead of setTimeout for anything long-running.
Worker goes idle
With no pending events, the browser may terminate the worker at any time. Nothing important should depend on it staying resident.
In practice this means: persist anything that matters, avoid long-lived timers in the background context, and use chrome.alarms for scheduled work instead of a setInterval that assumes the worker will still be running later.

Network rules without blocking webRequest
declarativeNetRequest replaces most blocking use of webRequest with a set of rules the browser evaluates natively: match a URL pattern, then block, redirect or modify headers. It is fast and does not expose request bodies to your code, which is also why it cannot express everything a fully custom callback could.
- Straightforward ad and tracker blocking by URL pattern maps onto declarativeNetRequest cleanly.
- Rules that depend on inspecting response bodies or making a decision per request based on external state need a different design, often moved into a content script or a native messaging host.
- Dynamic rules can still be added and removed at runtime, so the rule set does not have to be fully static, but it is still a rules engine rather than arbitrary code in the request path.
Permissions: ask for less, ask at the right time
Manifest V3 makes it easier to request host permissions at runtime instead of declaring broad access in the manifest up front. Store reviewers and users both read the permissions list as a signal of how much an extension can see, and a narrower request list is both a better user experience and a smoother path through review.
A reasonable default approach
Request the narrowest permission that satisfies the current feature, using optional permissions for anything that only some users will need, and explain in the extension’s own UI why a permission prompt is appearing before the browser shows it.
Chrome, Edge, Brave, Firefox and Safari are not one target
Manifest V3 is a Chromium specification, and Edge and Brave inherit it directly since they share Chromium’s extension platform. Firefox implements the WebExtensions API that Manifest V3 is largely based on, but its manifest keys, background page options and store policies are its own. Safari is the furthest outlier.
| Browser | Extension platform | What is different |
|---|---|---|
| Chrome / Edge / Brave | Manifest V3 (Chromium) | Share the same core APIs; store policies and review timelines differ per vendor |
| Firefox | WebExtensions, with Manifest V3 support | Some manifest keys and background-script details differ from Chromium’s implementation |
| Safari | Safari Web Extensions | Ships inside a native macOS/iOS app wrapper, built and signed on macOS, via Apple’s extension converter or a native project |
If a single extension needs to reach all of these, plan for a shared core with a small per-browser packaging and manifest layer, rather than assuming one manifest file will work unmodified everywhere. Our pages on Chrome extension development, Firefox extension development and Safari extension development cover what changes for each target.
Before you submit for review
- Confirm the extension works with the service worker actually terminating between events, not just in a long-running local dev session where it happens to stay alive.
- Re-read the permissions list as a store reviewer would, and remove anything not used by a shipped feature.
- Test the update path: users update in place, and a service worker rewrite that silently drops stored state on upgrade is a common source of support tickets.
- Run the extension through a real QA pass across the browsers you target, not just the one you built it in. Our browser and extension QA and extension security review services exist for exactly this stage.
When an extension stops being enough
Extensions are the right tool for a large share of browser feature work, but the platform has real edges. If a requirement needs browser UI that extension APIs do not expose, network or process behavior that declarativeNetRequest cannot express, or policy enforcement across managed devices beyond what enterprise extension controls allow, that is usually a sign the work belongs in a custom browser build instead. Our guide to Chromium covers how that decision plays out in practice.
Frequently asked questions
Is Manifest V2 still usable?
Chrome has been phasing out Manifest V2 for most users, and new listings on the Chrome Web Store have required Manifest V3 for some time. Firefox has supported Manifest V3 alongside its own extension APIs, on its own timeline. If you maintain an older extension, plan a migration rather than assuming V2 will keep working indefinitely, and check each browser vendor’s current policy before committing to a date.
Why does my background service worker keep losing state?
Manifest V3 replaced the persistent background page with a service worker that the browser can terminate whenever it is idle, then wake up again on the next event. Any variable held only in memory is lost when that happens. State that needs to survive has to go into chrome.storage, IndexedDB, or another persistent store, and the worker has to be written to reload what it needs each time it wakes up.
Can an extension still block network requests in Manifest V3?
Chrome removed blocking webRequest for most extensions and replaced it with declarativeNetRequest, which works from a set of rules the browser evaluates itself rather than a callback your code runs on every request. It covers most ad-blocking and content-filtering use cases, but it is a rules engine, not arbitrary code, so some historically webRequest-based patterns need to be redesigned around it.
Do I need a separate build for Firefox and Safari?
Often yes, at least in part. Firefox supports the WebExtensions API that Manifest V3 is based on, but its manifest and background-script details are not identical to Chrome’s. Safari extensions ship as Safari Web Extensions inside a native app wrapper, built and signed on macOS, and while Apple provides a conversion tool for existing extensions, the packaging and store process is its own path.
How long does Chrome Web Store review take?
Review times vary and are not guaranteed, and can be longer for extensions that request sensitive permissions or that are updated frequently. Build review time into your release planning, keep permission requests narrow and clearly justified, and expect additional scrutiny for changes to already-published extensions with a large install base.
When is an extension not enough?
If you need to change browser UI outside what extension APIs expose, alter networking or process behavior at a level declarativeNetRequest and similar APIs do not reach, or enforce policy across a fleet of managed devices beyond what enterprise extension policies allow, that usually means a custom Chromium or Firefox build rather than an extension. See our comparison in our guide on What Is Chromium for how that decision is usually made.
Final takeaway
Manifest V3 is more restrictive than V2 on a handful of specific axes, and more forgiving on almost everything else once an extension is designed around those restrictions instead of fighting them. Teams that treat the service worker lifecycle and the permissions model as first-class design constraints, not an afterthought during migration, tend to ship faster and pass review with fewer round trips.
Building or migrating an extension?
We build and migrate extensions across Chrome, Edge, Firefox, Brave and Safari, and can review an existing Manifest V2 codebase before you commit to a migration plan.
