Key version
The value must be a non-empty string.
version, or scope the key to
the loosest grammar all three already accept without a warning?
Grammar accepted today:
-
Chrome: 1 to 4 dot-separated integers. No leading zero in the first component; a leading zero in a later component is accepted and normalized, with a warning. Anything else fails to load.
-
Firefox: any string. A documented preferred grammar exists and a mismatch warns, but the value is used as-is. Firefox’s comparator also treats a non-numeric part of the value as meaningful rather than invalid (see § 1.2 Comparing version strings).
-
Safari: no grammar at all. Only emptiness is checked, and that does not block loading at the engine level.
Tracked at w3c/webextensions#283.
Key version_name
An optional string providing a version to show to users in place of
version, for example to include a channel qualifier such
as "1.2 beta". It has no effect on version comparison and is
not required to follow the version string grammar. The key is
OPTIONAL, and an implementation MAY ignore it.
version_name as a manifest key. This makes
version_name a two-of-three feature: Chrome and Safari support it as
display text that falls back to version when absent or empty. Firefox
has stated the omission is deliberate, not an oversight: bugzilla
1380219,
RESOLVED WONTFIX, records the decision, reasoning that the version
string is part of an extension’s identity and a customizable display
string risks confusing users.
1. Version number handling
1.1. The version string
An extension’s version string is the value of its
version manifest key.
To parse a version string given input:
-
Let parts be the result of strictly splitting input on U+002E (.).
-
If parts contains the empty string, return failure.
-
Let components be an empty list.
-
For each part of parts:
-
Return components.
-
Is the number of components capped (Chrome allows at most 4)?
-
Is each component’s value capped (Chrome allows 0 to 4294967295)?
Firefox and Safari accept a version string that fails this algorithm, storing the value unchanged.
1.2. Comparing version strings
To compare two version strings given versionA and versionB:
-
Let a be the result of parsing versionA.
-
Let b be the result of parsing versionB.
-
If a or b is failure, return failure.
-
Let n be the larger of a’s and b’s size.
-
For each i in the range 0 to n, exclusive:
-
Return "equal".
"4294967295.0" and "1.0" both parse
successfully under Chrome’s grammar and under Firefox’s (Firefox only warns
about the 10-digit first component; it does not reject it). Chrome and
Firefox order them oppositely:
-
Chrome parses the first component as the literal integer 4294967295 (it fits exactly in a 32-bit unsigned value) and so treats
"4294967295.0"as newer than"1.0". -
Firefox’s comparator parses the same component as a signed 32-bit integer; 4294967295 overflows that type, and Firefox silently substitutes 0 on overflow rather than rejecting the value or saturating it. Firefox therefore treats
"4294967295.0"as equal to"0.0", and so older than"1.0".
Chrome and Firefox disagree about which of "4294967295.0" and "1.0" is
newer, for two version strings both accept without error.
Chrome’s comparator performs the numeric tuple compare given above. Firefox and Safari:
-
Firefox: compares each part as a number followed by a string, so it can order pairs Chrome cannot compare at all, such as
1.0a1against1.0b1. A number outside the representable range silently becomes 0. -
Safari: no comparison exists in the engine. The version is stored and returned as an opaque string, and any comparison for update purposes happens in the host application.
1.3. Invalid version strings
A version string that does not parse is
invalid. Chrome, Firefox, and Safari each treat an invalid or empty
version differently from an absent key.
version is invalid, and if so, is the whole
extension rejected, or only the key?
The consequence today, including for the specific case of an empty
version, which the normative requirement above
(Key version) already forbids:
-
Chrome: the extension fails to load, with an install error. An empty string is included in this: it fails to parse the same as any other unparseable value, so it is rejected, not treated as though the key were absent.
-
Firefox: the extension loads. Any string is used as-is, including an empty one, with a console warning when it does not match the documented preferred grammar. Firefox does not conform to the non-empty requirement above: an empty
versionis accepted and its value retained, not rejected and not treated as though the key were absent. -
Safari: the engine records an error for an empty or otherwise unparseable value but does not itself refuse to load the extension; this is by the engine’s own documented design, which defers the decision to the embedding application rather than leaving it unimplemented. Whether Safari itself then blocks installation on that error is a decision made in Safari’s own application code, which is not part of any open source tree.
1.4. Observability to extensions
Version comparison is not exposed to extension JavaScript as an API in any of the three browsers examined; it is purely an install/update-time concern of the browser.
runtime.getManifest() returns the version string exactly as authored, unmodified, in Chrome, Firefox, and Safari: it reads
directly from the parsed manifest object rather than from any canonicalized
form.
runtime.getVersion() is a required method
(w3c/webextensions#878, closed 2026-04-08).
Whether it returns the literal manifest string or a canonicalized form is
implementation-defined. Chrome canonicalizes its input before returning it,
so calling it can return a string different from runtime.getManifest().version
for the same extension (for example "1.002.3" in the manifest becomes
"1.2.3" from getVersion()); Safari performs no canonicalization, so the
two calls always agree. Firefox does not implement runtime.getVersion()
yet.