DEV Community

Cover image for Create, Debug, and Publish Firefox Extensions: A Full Developer Guide Step by Step
Md Mahbubur Rahman
Md Mahbubur Rahman

Posted on

Create, Debug, and Publish Firefox Extensions: A Full Developer Guide Step by Step

Table of Contents

  1. Introduction
  2. Why Firefox Extensions Matter
  3. Understanding WebExtensions Architecture
  4. Setting Up Your Development Environment
  5. Anatomy of a Firefox Extension
  6. Creating Your First Extension
  7. Background Scripts
  8. Content Scripts
  9. Popup & Options Page UI
  10. Messaging and Event Handling
  11. Storage and Data Management
  12. Permissions and Security Best Practices
  13. Intermediate Features
  14. Advanced Features
  15. Debugging and Troubleshooting
  16. Publishing on AMO
  17. Common Mistakes
  18. Performance Optimization
  19. Real-World Example: Text Saver Extension
  20. Conclusion

1. Introduction

Developing a Firefox extension empowers you to customize, automate, and enhance the browsing experience. Unlike traditional web apps, extensions can modify pages in real-time, interact with browser APIs, and provide tools that millions of users can rely on. Firefox supports the WebExtensions API, making it compatible across Chrome, Edge, and Opera, allowing portability of skills and code.

This guide takes you from beginner concepts to advanced techniques. By the end, you will understand how to structure, code, debug, optimize, and publish Firefox extensions, all in a professional, human-written style.


2. Why Firefox Extensions Matter

Firefox extensions remain relevant due to three key reasons:

  1. Flexibility: Firefox supports a broad set of APIs, including some advanced features not yet in Chrome’s Manifest V3.
  2. Open Development: Tools like web-ext make building, testing, and debugging easy.
  3. User Base: Firefox users are privacy-conscious and willing to adopt productivity or customization extensions.

Developing for Firefox first can help you iterate quickly and build a robust foundation before deploying to other browsers.


3. Understanding WebExtensions Architecture

Extensions consist of several components:

  • Background Script: Runs persistently or as a service worker. Handles events, coordinates components, and manages storage.
  • Content Script: Injected into web pages to manipulate the DOM, read data, and send messages to the background.
  • Popup UI: Small HTML-based interface for user interaction.
  • Options Page: Full-page interface for user settings and configurations.
  • Manifest File: JSON file defining permissions, scripts, UI elements, and extension metadata.
+-------------------+
| Browser UI        |
| (Toolbar)         |
+---------+---------+
          |
       Popup UI
          |
+---------+---------+       +---------------------+
| Background Script | <----> | Content Scripts    |
+------------------+       +---------------------+
Enter fullscreen mode Exit fullscreen mode

4. Setting Up Your Development Environment

Required Tools:

  • Firefox Developer Edition
  • Code editor (VS Code recommended)
  • Node.js (for web-ext)

Install web-ext globally:

npm install --global web-ext
Enter fullscreen mode Exit fullscreen mode

Optional Tools:

  • ESLint & Prettier
  • Git for version control
  • Browser DevTools for extensions

5. Anatomy of a Firefox Extension

Example project structure:

firefox-extension/
├── manifest.json
├── background.js
├── content.js
├── popup.html
├── popup.js
├── options.html
├── options.js
└── icons/icon48.png
Enter fullscreen mode Exit fullscreen mode

Manifest.json Example

{
  "manifest_version": 3,
  "name": "Text Saver",
  "version": "1.0",
  "description": "Save selected text from any webpage.",
  "permissions": ["storage", "activeTab", "scripting"],
  "host_permissions": ["<all_urls>"],
  "action": {
    "default_title": "Save Selected Text",
    "default_popup": "popup.html",
    "default_icon": "icons/icon48.png"
  },
  "background": {
    "service_worker": "background.js"
  },
  "options_ui": {
    "page": "options.html",
    "open_in_tab": true
  }
}
Enter fullscreen mode Exit fullscreen mode

6. Creating Your First Extension

Background Script

browser.runtime.onMessage.addListener(async (msg) => {
  if (msg.action === "saveText") {
    let saved = await browser.storage.local.get("notes");
    let notes = saved.notes || [];
    notes.push({ text: msg.payload, time: Date.now() });
    await browser.storage.local.set({ notes });
    return { status: "ok" };
  }
});
Enter fullscreen mode Exit fullscreen mode

Content Script

let selection = window.getSelection().toString().trim();
if (selection) {
  browser.runtime.sendMessage({ action: "saveText", payload: selection });
}
Enter fullscreen mode Exit fullscreen mode

Popup HTML

<!DOCTYPE html>
<html>
  <body>
    <button id="saveBtn">Save Selected Text</button>
    <ul id="list"></ul>
    <script src="popup.js"></script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Popup JS

document.getElementById("saveBtn").onclick = async () => {
  let tabs = await browser.tabs.query({ active: true, currentWindow: true });
  await browser.scripting.executeScript({ target: { tabId: tabs[0].id }, files: ["content.js"] });
};

(async () => {
  let stored = await browser.storage.local.get("notes");
  let notes = stored.notes || [];
  let list = document.getElementById("list");
  notes.forEach(n => {
    let li = document.createElement("li");
    li.textContent = n.text;
    list.appendChild(li);
  });
})();
Enter fullscreen mode Exit fullscreen mode

7. Intermediate Features

  • Dynamic Script Injection: browser.scripting.executeScript(...)
  • Context Menus: browser.contextMenus.create(...)
  • Keyboard Shortcuts: define in manifest under commands
  • Storage Sync vs Local: choose based on need for cross-device persistence

8. Advanced Features

  • Native Messaging: communicate with local apps.
  • OAuth Authentication: login via identity.launchWebAuthFlow.
  • IndexedDB: handle large datasets.
  • Performance: throttle content scripts, lazy-load modules.
  • Cross-browser compatibility: prefer browser.* APIs.

9. Debugging & Troubleshooting

  • Use Firefox DevTools for service worker and content scripts.
  • Check console for messages and errors.
  • Use web-ext lint to validate manifest and permissions.
  • Common issues:
    • Content script not running → check host_permissions
    • Background not responding → check service worker lifecycle
    • Popup not updating → popups unload on close

10. Publishing on AMO

  • Build using web-ext build
  • Submit to addons.mozilla.org
  • Follow permissions, CSP, and security guidelines
  • Include clear description, icons, screenshots
  • Respond to review feedback promptly

11. Common Mistakes

  • Heavy logic in popups
  • Over-injecting content scripts
  • Ignoring asynchronous APIs
  • Overusing permissions
  • Not caching repeated results

12. Performance Optimization

  • Keep content scripts minimal
  • Use event-driven background scripts
  • Lazy-load libraries
  • Optimize storage queries
  • Avoid blocking UI updates

13. Real-World Example: Text Saver Extension

Combines all the above concepts: content scripts, background scripts, popup, storage, messaging, and permissions. Ready to package and publish.


14. Conclusion

Firefox extensions provide developers with unparalleled opportunities to improve the web experience. By combining beginner-friendly examples with advanced techniques, you can build robust, maintainable, and secure extensions that users love. Starting with small projects like a Text Saver extension allows iterative learning before tackling more complex, real-world solutions.

Top comments (0)