Manifest
In WXT, there is no manifest.json file in your source code. Instead, WXT generates the manifest from multiple sources:
- Global options defined in your
wxt.config.tsfile - Entrypoint-specific options defined in your entrypoints
- WXT Modules added to your project can modify your manifest
- Hooks defined in your project can modify your manifest
Your extension's manifest.json will be output to .output/{target}/manifest.json when running wxt build.
Global Options
To add a property to your manifest, use the manifest config inside your wxt.config.ts:
export default defineConfig({
manifest: {
// Put manual changes here
},
});You can also define the manifest as a function, and use JS to generate it based on the target browser, mode, and more.
export default defineConfig({
manifest: ({ browser, manifestVersion, mode, command }) => {
return {
// ...
};
},
});MV2 and MV3 Compatibility
When adding properties to the manifest, always define the property in it's MV3 format when possible. When targeting MV2, WXT will automatically convert these properties to their MV2 format.
For example, for this config:
export default defineConfig({
manifest: {
action: {
default_title: 'Some Title',
},
web_accessible_resources: [
{
matches: ['*://*.google.com/*'],
resources: ['icon/*.png'],
},
],
},
});WXT will generate the following manifests:
{
"manifest_version": 2,
// ...
"browser_action": {
"default_title": "Some Title"
},
"web_accessible_resources": ["icon/*.png"]
}{
"manifest_version": 3,
// ...
"action": {
"default_title": "Some Title"
},
"web_accessible_resources": [
{
"matches": ["*://*.google.com/*"],
"resources": ["icon/*.png"]
}
]
}You can also specify properties specific to a single manifest version, and they will be stripped out when targeting the other manifest version.
Name
If not provided via the manifest config, the manifest's name property defaults to your package.json's name property.
Version and Version Name
Your extension's version and version_name is based on the version from your package.json.
version_nameis the exact string listedversionis the string cleaned up, with any invalid suffixes removed
Example:
// package.json
{
"version": "1.3.0-alpha2"
}// .output/<target>/manifest.json
{
"version": "1.3.0",
"version_name": "1.3.0-alpha2"
}If a version is not present in your package.json, it defaults to "0.0.0".
Icons
WXT automatically discovers your extension's icon by looking at files in the public/ directory:
public/
├─ icon-16.png
├─ icon-24.png
├─ icon-48.png
├─ icon-96.png
└─ icon-128.pngSpecifically, an icon must match one of these regex to be discovered:
const iconRegex = [
/^icon-([0-9]+)\.png$/, // icon-16.png
/^icon-([0-9]+)x[0-9]+\.png$/, // icon-16x16.png
/^icon@([0-9]+)w\.png$/, // icon@16w.png
/^icon@([0-9]+)h\.png$/, // icon@16h.png
/^icon@([0-9]+)\.png$/, // icon@16.png
/^icons?[/\\]([0-9]+)\.png$/, // icon/16.png | icons/16.png
/^icons?[/\\]([0-9]+)x[0-9]+\.png$/, // icon/16x16.png | icons/16x16.png
];If you don't like these filename or you're migrating to WXT and don't want to rename the files, you can manually specify an icon in your manifest:
export default defineConfig({
manifest: {
icons: {
16: '/extension-icon-16.png',
24: '/extension-icon-24.png',
48: '/extension-icon-48.png',
96: '/extension-icon-96.png',
128: '/extension-icon-128.png',
},
},
});Alternatively, you can use @wxt-dev/auto-icons to let WXT generate your icon at the required sizes.
Permissions
Most of the time, you need to manually add permissions to your manifest. Only in a few specific situations are permissions added automatically:
- During development: the
tabsandscriptingpermissions will be added to enable hot reloading. - When a
sidepanelentrypoint is present: Thesidepanelpermission is added.
export default defineConfig({
manifest: {
permissions: ['storage', 'tabs'],
},
});Host Permissions
export default defineConfig({
manifest: {
host_permissions: ['https://www.google.com/*'],
},
});WARNING
If you use host permissions and target both MV2 and MV3, make sure to only include the required host permissions for each version:
export default defineConfig({
manifest: ({ manifestVersion }) => ({
host_permissions: manifestVersion === 2 ? [...] : [...],
}),
});Default Locale
export default defineConfig({
manifest: {
name: '__MSG_extName__',
description: '__MSG_extDescription__',
default_locale: 'en',
},
});See I18n docs for a full guide on internationalizing your extension.
Actions
In MV2, you have two options: browser_action and page_action. In MV3, they were merged into a single action API.
By default, whenever an action is generated, WXT falls back to browser_action when targeting MV2.
Action With Popup
To generate a manifest where a UI appears after clicking the icon, just create a Popup entrypoint. If you want to use a page_action for MV2, add the following meta tag to the HTML document's head:
<meta name="manifest.type" content="page_action" />Action Without Popup
If you want to use the activeTab permission or the browser.action.onClicked event, but don't want to show a popup:
Delete the Popup entrypoint if it exists
Add the
actionkey to your manifest:tsexport default defineConfig({ manifest: { action: {}, }, });
Same as an action with a popup, WXT will fallback on using browser_action for MV2. To use a page_action instead, add that key as well:
export default defineConfig({
manifest: {
action: {},
page_action: {},
},
});