Skip to main content
Keep extension builds predictable by treating manifest.json as the source of truth for entrypoints, assets, and browser-specific behavior. Extension.js compiles your manifest and filters browser-prefixed fields. It rewrites runtime paths, validates referenced files, and produces a ready-to-load manifest for each target browser.

Manifest capabilities

Where Extension.js reads the manifest

  • src/manifest.json (preferred when present)
  • manifest.json at project root
Extension.js does not use public/manifest.json as the source manifest. A manifest.json under public/ fails the build with manifest.json must not be placed under public/. Move it to src/manifest.json or the project root, so a copied static asset never overwrites the manifest that Extension.js generates.

What Extension.js does with it

During dev/build, the manifest pipeline:
  1. Emits the manifest asset from your source file.
  2. Filters browser-prefixed keys for the active browser target.
  3. Applies manifest overrides/path normalization for extension outputs.
  4. Validates referenced files (HTML/scripts/CSS/icons/JSON) and fails early when missing.

One manifest, multiple browsers

Browser-prefixed keys let you keep one manifest file while still targeting browser-specific behavior:
  • chromium:*, chrome:*, edge:*
  • firefox:*, gecko:*
These prefixes can apply to top-level keys and nested manifest fields. Examples:
  • chromium:key
  • background.firefox:scripts
  • background.chromium:service_worker

Supported manifest fields

Common entrypoint-related fields include:

Permissions design

The manifest is also where your extension declares what it can do. Extension.js compiles the manifest, but you still need good permission design.
  • Keep permissions small and intentional.
  • Keep host_permissions as narrow as the feature allows.
  • Move non-core capabilities into optional_permissions or optional_host_permissions where possible.
  • Review permission scope whenever content-script matches or background capabilities change.
For permission strategy, see Permissions and host permissions.

Output behavior

Extension.js rewrites manifest paths to predictable output locations when needed. Two important examples:
  • background.service_worker becomes background/service_worker.js
  • side_panel.default_path becomes sidebar/index.html
  • page_action.default_popup becomes page_action/index.html, its own page beside the toolbar popup, on Firefox (any manifest version) and on Chromium MV2. When page_action and action (or browser_action) name the same file, both keys share action/index.html. Chromium MV3 has no page action surface, so the build drops page_action from that manifest with a warning and emits no page for it.
Extension.js also normalizes content scripts by manifest entry index:
  • content_scripts/content-0.js
  • content_scripts/content-0.css
Those emitted paths are what the browser actually loads. Use source paths in authoring, then let Extension.js rewrite them for output.

Development behavior

  • When manifest.json changes, Extension.js recompiles and triggers extension hard reload flow.
  • If manifest entrypoint structure changes (for example, script list changes), Extension.js may require a dev server restart.
  • Missing files referenced by manifest fields fail compilation with manifest-focused errors.

Change outcome matrix

What Extension.js repairs for you

Some manifest shapes make Chromium refuse to load the extension outright, with little explanation. Extension.js diagnoses these before the browser launches and auto-repairs the fatal ones. Each repair prints a warning that names the field and the reason. See Manifest refusals for the catalogue of refusal causes and repairs.

Legacy path warnings

Development and production builds both warn when the emitted manifest still contains one of these deprecated generated paths:
  • devtools_page/devtools_page.html
  • options_ui/page.html
  • background/page.html
  • browser_action/default_popup.html
  • page_action/default_popup.html
  • side_panel/default_path.html
  • sidebar_action/default_panel.html
Each match produces a ManifestLegacyWarning. Extension.js rewrites these paths to the standardized folders in the next major version.

Best practices

  • Keep manifest paths relative to the extension source/output model and use leading / only when you mean extension output root.
  • Use browser-prefixed keys instead of maintaining separate manifest files per browser.
  • Keep entrypoint changes deliberate; adding/removing manifest scripts often changes reload semantics in dev.
  • Validate icons, JSON resources, and content-script assets as part of continuous integration (CI) to catch path regressions early.
  • Do not place manifest.json under public/.

Next steps

Video walkthrough