Skip to content

/flags/semver/semver-c-coerce

semver -c (--coerce): turn v2, 1.2 or 'nginx/1.27.4' into a valid version

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash)updated
tool
SemVer
command
semver
flag
-c, --coerce
default
off (strings that are not valid SemVer are rejected and semver exits with 1)

semver -c "v2" prints 2.0.0, semver -c "1.2" prints 1.2.0, and semver -c "nginx/1.27.4 (Ubuntu)" prints 1.27.4: coercion finds the first group of one to three dot-separated numbers in the input and turns it into a valid SemVer MAJOR.MINOR.PATCH, padding missing parts with zero. It is the way to compare versions reported by tools (python --version, openssl version, a Git tag) that are not strict SemVer. Without -c, semver accepts only valid versions and exits with 1 otherwise.

Coercing real-world version strings

node-semver's CLI is installed in a temporary folder (npx semver behaves the same):

bash
npm init -y >/dev/null && npm install --silent --no-audit --no-fund semver@7.8.5 >/dev/null 2>&1
export PATH="$PWD/node_modules/.bin:$PATH"
for v in v2 "version 1.2" 1.2.3.4 "nginx/1.27.4 (Ubuntu)" "Python 3.13.15" "OpenSSL 3.5.7 9 Jun 2026" release-2024.10 1.2.3-beta.1; do
  printf '%-28s -> %s\n' "$v" "$(semver -c "$v")"
done
echo "--- right to left:"; semver -c --rtl 1.2.3.4
echo "--- keep the prerelease with -p:"; semver -c -p "v1.2.3-beta.2+build"
echo "--- without -c:"; semver "version 1.2"; echo "exit $?"
echo "--- nothing to coerce:"; semver -c "latest"; echo "exit $?"
echo "--- coerce, then filter by range:"; semver -c 1.2.3 1.10 2 -r ">=1.5"

Output

v2                           -> 2.0.0
version 1.2                  -> 1.2.0
1.2.3.4                      -> 1.2.3
nginx/1.27.4 (Ubuntu)        -> 1.27.4
Python 3.13.15               -> 3.13.15
OpenSSL 3.5.7 9 Jun 2026     -> 3.5.7
release-2024.10              -> 2024.10.0
1.2.3-beta.1                 -> 1.2.3
--- right to left:
2.3.4
--- keep the prerelease with -p:
1.2.3-beta.2
--- without -c:
exit 1
--- nothing to coerce:
exit 1
--- coerce, then filter by range:
1.10.0
2.0.0

Text around the numbers is ignored, a fourth component is dropped, and a prerelease suffix is removed unless -p is given. A string with no digits at all cannot be coerced: semver prints nothing and exits with 1. Combined with -r, every argument is coerced first and then filtered by the range.

Rules of coercion

InputResultRule
v22.0.0Missing minor and patch become 0
1.21.2.0Same, with one number missing
1.2.3.41.2.3 (2.3.4 with --rtl)At most three numbers are used
nginx/1.27.4 (Ubuntu)1.27.4Leading and trailing text is ignored
1.2.3-beta.11.2.3 (1.2.3-beta.1 with -p)Prerelease dropped unless -p
latest(nothing, exit 1)No digits to use

When to use it, and when not

Coercion is ideal for "is the installed tool new enough?" checks:

bash
have=$(semver -c "$(openssl version)")
semver -r ">=3.0.0" "$have" >/dev/null || echo "OpenSSL 3 required, found $have"

Do not use it to validate input that is supposed to be SemVer (package versions, release tags): coercion happily turns 1.2.3.4-hotfix or v2-final into something valid and hides the mistake. Validate strictly instead, as on validate a SemVer string, and handle the library's TypeError: Invalid Version.

Pitfalls

  • Date-like versions. release-2024.10 becomes 2024.10.0, which sorts correctly against other dates but is not a semantic version in spirit.
  • Leading zeros. v01.02.03 is not coerced in node-semver 7.8 (it prints nothing); strip the zeros first.
  • Shell comparison. For simple numeric comparisons without Node, sort -V is an alternative; see compare two versions in bash. For malformed but nearly valid versions, semver -l may be the better choice.

FAQ

Does --coerce keep the prerelease part?

Not by default: semver -c 1.2.3-beta.1 prints 1.2.3. Add -p (include prerelease), which in node-semver 7.8 keeps prerelease and build parts when coercing: v1.2.3-beta.2+build becomes 1.2.3-beta.2.

What does --rtl do?

It reads the string right to left, so in 1.2.3.4 the last three numbers are used (2.3.4) instead of the first three (1.2.3). This helps with version strings that carry a prefix number, such as a product generation.

Is coercion the same as loose parsing?

No. --loose accepts slightly malformed versions such as =v1.2.3 or 1.2.3beta as they are; --coerce extracts the first version-like number group from any text and fills in missing minor and patch numbers with 0.

Sources