Manifest
In WXT, there is no manifest.json
file in your source code. Instead, WXT generates it during the build process based off files in your project.
Manifest Config
To manually add a property to the manifest.json
output during builds, use the manifest
config inside 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_name
is the exact string listedversion
is 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.png
Specifically, if 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
export default defineConfig({
manifest: {
permissions: ['storage', 'tabs'],
},
});
Host Permissions
export default defineConfig({
manifest: {
permissions: ['storage', 'tabs'],
},
});
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.
export default defineConfig({
hooks: {
build: {
manifestGenerated(manifest) {
// Update the manifest variable by reference
manifest.name = 'Overriden name';
},
},
},
});
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
action
key 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: {},
},
});