Install & Compatibility
Where this runs
tested against v? · npm install
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslnode 18–226 runs
build_error
glibcnode 18–226 runs
build_error
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
webExt.cmd.run
✓ import webExt from 'web-ext';
webExt.cmd.run({
sourceDir: './path/to/your/extension/source',
firefox: 'developer',
}, {
shouldExitProgram: false,
});
✗ const webExt = require('web-ext'); // CommonJS is not natively supported since v7.0.0; dynamic import or ESM required.
// webExt.run(); // Incorrect API usage, functions are nested under .cmd
web-ext is primarily a CLI tool. Direct programmatic use is supported for ESM (Node.js native ES modules) since v7.0.0. CommonJS `require()` syntax requires dynamic imports. The API is considered internal and may have breaking changes in minor versions.
webExt.cmd.lint
✓ import webExt from 'web-ext';
async function lintExtension() {
try {
const results = await webExt.cmd.lint({
sourceDir: './path/to/your/extension/source',
// Optional: Set strict_min_version to '100' for stricter checks
}, {
shouldExitProgram: false,
});
console.log('Linting complete:', results.summary);
} catch (error) {
console.error('Linting failed:', error);
}
}
lintExtension();
✗ import { lint } from 'web-ext'; // Incorrect named import for command functions.
webExt.lint(); // Incorrect direct call, requires .cmd prefix and options object.
Like other commands, `lint` is accessible via `webExt.cmd`. It returns validation results and can be configured with options like `sourceDir` and `strict_min_version`.
Using via `npx` or `npm` scripts
✓ npx web-ext run --source-dir ./extension-dist --firefox=nightly
✗ node path/to/web-ext.js run --source-dir ./extension-dist // While technically possible, `npx` or global installation is the intended CLI usage.
The most common and recommended way to use web-ext for developers is via global installation (`npm install -g web-ext`), `npx`, or as an `npm script` in `package.json`. This abstracts away the Node.js API and leverages the CLI directly.
This quickstart demonstrates how to run a web extension in Firefox using `web-ext` via `child_process.spawn` from a Node.js script. It creates a minimal extension and launches Firefox with it, showing how to leverage `web-ext`'s CLI capabilities programmatically, which is the primary integration pattern.
import { spawn } from 'child_process';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const extensionSourceDir = path.join(__dirname, 'my-browser-extension');
console.log(`Starting web-ext to run extension from: ${extensionSourceDir}`);
const webExtProcess = spawn('npx', [
'web-ext',
'run',
'--source-dir', extensionSourceDir,
'--browser-console',
'--firefox-profile', 'web-ext-dev-profile',
'--keep-profile-changes',
'--watch-file', path.join(extensionSourceDir, '**/*'),
'--devtools'
], {
stdio: 'inherit',
shell: true
});
webExtProcess.on('error', (err) => {
console.error('Failed to start web-ext process:', err);
});
webExtProcess.on('close', (code) => {
console.log(`web-ext process exited with code ${code}`);
});
// Example: Create a dummy extension directory for demonstration
import { mkdirSync, writeFileSync, existsSync } from 'fs';
if (!existsSync(extensionSourceDir)) {
mkdirSync(extensionSourceDir, { recursive: true });
mkdirSync(path.join(extensionSourceDir, 'icons'), { recursive: true });
writeFileSync(path.join(extensionSourceDir, 'manifest.json'), JSON.stringify({
"manifest_version": 2,
"name": "My Basic Extension",
"version": "1.0",
"description": "A simple extension generated by web-ext quickstart.",
"icons": {
"48": "icons/icon-48.png"
},
"browser_action": {
"default_popup": "popup/popup.html"
}
}, null, 2));
mkdirSync(path.join(extensionSourceDir, 'popup'), { recursive: true });
writeFileSync(path.join(extensionSourceDir, 'popup/popup.html'), '<!DOCTYPE html><html><body><h1>Hello web-ext!</h1></body></html>');
writeFileSync(path.join(extensionSourceDir, 'icons/icon-48.png'), '<!-- Base64 encoded dummy image data for a 48x48 transparent PNG -->');
console.log('Dummy extension created in:', extensionSourceDir);
}
// To stop the process programmatically (optional, for longer-running tasks)
// setTimeout(() => {
// console.log('Attempting to kill web-ext process...');
// webExtProcess.kill();
// }, 60000); // Kills after 60 seconds
web-ext --version
Errors
Common errors & fixes
Error: Cannot find module 'web-ext' from '...' or 'require() of ES Module .../node_modules/web-ext/index.js from .../your-script.js not supported.'
Attempting to `require('web-ext')` in a CommonJS module, but `web-ext` >=7.0.0 is an ESM-only package.
fixUse dynamic import: `const webExt = await import('web-ext');` or refactor your script to use ES modules (`.mjs` file or `"type": "module"` in `package.json`). WARNING: config file <path>.js should be renamed to ".cjs" or ".mjs" file extension to ensure its format is not ambiguous. Config files with the ".js" file extension are deprecated and will not be loaded anymore in a future web-ext major version.
Using a `.js` file for web-ext configuration, which is deprecated and no longer supported since v9.0.0.
fixRename your configuration file from `.js` to `.cjs` (for CommonJS export) or `.mjs` (for ESM default export). Update the export syntax if necessary (e.g., `module.exports = { ... }` or `export default { ... }`). Error: Missing required argument: --api-key and --api-secret (or environment variables WEB_EXT_API_KEY and WEB_EXT_API_SECRET)
Attempting to use `web-ext sign` without providing API credentials for addons.mozilla.org (AMO).
fixWhen using `web-ext sign`, you must provide your AMO API key and secret either via command-line arguments (`--api-key <key> --api-secret <secret>`) or as environment variables (`WEB_EXT_API_KEY` and `WEB_EXT_API_SECRET`). Obtain these credentials from the AMO developer hub.
Audit
Dependencies
addons-linterrequiredUsed for validating extension source code and manifest files against browser schemas.
pinorequiredUsed for logging within the web-ext tool.
openrequiredUsed to open URLs or files in the default browser, for example, opening documentation.