Firefox XPI File Structure and Manifest Guide

This article provides a comprehensive breakdown of the .xpi file format used for Firefox browser extensions. It covers the fundamental ZIP-based architecture of the package, the standard internal directory structure, the critical role and syntax of the manifest.json configuration file, and the cryptographic security files generated by Mozilla during the signing process.

What is an XPI File?

An .xpi (pronounced "zippy" and derived from Cross-Platform Install) file is a standard ZIP archive with a renamed file extension. Firefox uses this format to package and distribute browser add-ons using the WebExtensions API. Because it is a standard ZIP file, its contents can be extracted and inspected using any standard decompression utility.

Internal Directory Structure

While the WebExtensions API allows developers flexibility in how they organize their code, a packaged .xpi file must follow specific rules for mandatory files. The manifest.json file must always reside at the exact root of the archive, not nested inside a subfolder.

A typical, well-structured .xpi package looks like this:

extension.xpi
├── manifest.json
├── META-INF/
│   ├── manifest.mf
│   ├── mozilla.rsa
│   └── mozilla.sf
├── _locales/
│   ├── en/
│   │   └── messages.json
│   └── es/
│       └── messages.json
├── background/
│   └── background.js
├── content_scripts/
│   └── inject.js
├── icons/
│   ├── icon-48.png
│   └── icon-96.png
└── popup/
    ├── popup.html
    ├── popup.css
    └── popup.js

Key Directories Explained

  • Root Directory: Must contain manifest.json. All relative paths in the manifest start from this root.
  • META-INF/: Contains digital signature files added by Mozilla when the extension is signed for distribution.
  • _locales/: A strictly named directory used for internationalization (i18n). If your extension supports multiple languages, the translations must go here, organized by language code.
  • Custom Directories (icons/, popup/, background/, etc.): These folders are not strictly enforced by Firefox. Developers create them by convention to keep HTML, CSS, JavaScript, and image assets organized. Firefox locates the files inside these folders based on the paths defined in manifest.json.

The manifest.json Structure

The manifest.json file is the blueprint of the extension. It is the only file that every extension must contain at the root level. It provides Firefox with metadata (name, version), defines the extension's capabilities, declares permissions, and points to the files that run in the background or on web pages.

Here is an example of a standard Firefox manifest.json file:

{
  "manifest_version": 3,
  "name": "Sample Firefox Extension",
  "version": "1.0.0",
  "description": "A clear example of a Firefox manifest.",
  "icons": {
    "48": "icons/icon-48.png",
    "96": "icons/icon-96.png"
  },
  "browser_specific_settings": {
    "gecko": {
      "id": "addon@example.com",
      "strict_min_version": "109.0"
    }
  },
  "permissions": [
    "storage",
    "activeTab"
  ],
  "background": {
    "scripts": ["background/background.js"]
  },
  "action": {
    "default_popup": "popup/popup.html",
    "default_icon": "icons/icon-48.png"
  },
  "content_scripts": [
    {
      "matches": ["*://*.mozilla.org/*"],
      "js": ["content_scripts/inject.js"]
    }
  ]
}

Breakdown of Manifest Keys

  • manifest_version: An integer specifying the version of the manifest file format (currently 2 or 3).
  • name, version, description: Basic strings identifying the extension in the Firefox Add-ons Manager.
  • icons: Maps icon pixel sizes to their relative file paths inside the .xpi archive.
  • browser_specific_settings: A key unique to Firefox (which uses the Gecko rendering engine). It defines the extension's unique id and the minimum Firefox version required.
  • permissions: An array of strings requesting access to specific browser APIs (like storage, tabs, or bookmarks).
  • background: Specifies long-running scripts or service workers that maintain the extension's state independent of any specific web page.
  • action (or browser_action in MV2): Defines the toolbar button, its icon, and the HTML file to load when a user clicks the button (default_popup).
  • content_scripts: Tells Firefox to inject specific JavaScript or CSS files into web pages that match the defined URL patterns.

The META-INF Directory (Cryptographic Signing)

For an .xpi file to be installed in standard release versions of Firefox, it must be cryptographically signed by Mozilla. When a developer uploads their ZIP file to Mozilla Add-ons (AMO), Mozilla verifies the code, generates the META-INF directory, packages everything together, and outputs the final .xpi file.

This directory contains three specific files that prevent tampering:

  1. manifest.mf: Contains a list of every file in the .xpi archive along with its cryptographic hash (usually SHA-256).
  2. mozilla.sf: A signature file that contains the cryptographic hash of the manifest.mf file itself.
  3. mozilla.rsa: The binary cryptographic signature of the mozilla.sf file, generated using Mozilla's private key, along with the certificate chain needed by Firefox to verify the signature.

When you install the .xpi file, Firefox checks mozilla.rsa to verify Mozilla signed it, uses mozilla.sf to verify manifest.mf hasn't changed, and finally checks manifest.mf to ensure none of the extension's scripts or assets were modified after signing. If any file is altered, the signature breaks, and Firefox will refuse to install or run the extension.