Semantic version regex
The official semver.org reference regex — major.minor.patch with optional pre-release and build metadata.
^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/What it matches
This is the canonical semver regex from semver.org. It enforces the full grammar: three numeric components, optional pre-release suffix (`-alpha.1`), and optional build metadata (`+build.42`). Numeric components can't have leading zeros, pre-release identifiers can be alphanumeric, and build metadata is appended after a `+`.
Examples
Matches
1.2.3Plain stable release.
0.0.1Zero-major, zero-minor, patch only.
2.0.0-alpha.1Pre-release with dot-separated identifiers.
2.0.0-rc.1+build.42Pre-release plus build metadata.
1.2.3+buildBuild metadata without a pre-release.
Does not match
1.2Missing patch component.
1.2.3.4Four components is not valid semver.
v1.2.3Leading `v` is convention, not semver — strip it first.
01.2.3Leading zero in the major component.
Edge cases & gotchas
- Allows pre-release identifiers like `0`, `1`, etc. (`1.0.0-0` is valid semver). Useful for `0`-indexed RC counts.
- Build metadata is IGNORED for version precedence per the spec — `1.2.3+a` and `1.2.3+b` are equal versions.
- Doesn't accept the `v` prefix common in tags. Strip with `s.replace(/^v/, '')` before matching, or add `v?` after `^`.
- Doesn't handle range specifiers like `^1.2.3` or `~1.2.3`. Those are package-manager grammar, not semver itself.
In your language
// JavaScript
const re = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
const match = "input".match(re);All 13 languages (including Bash, Perl, Kotlin, Swift) available in the full toolkit Export tab.
Notes for production
- If you're parsing npm or Cargo version specifiers, use a dedicated library (`semver` package on npm) — they understand caret/tilde/x-ranges and comparison.
- Tag normalization: many ecosystems use `v1.2.3` in git tags but bare `1.2.3` in package.json. Strip the `v` once at the boundary.
Frequently asked
Why does my version with a `v` prefix fail?
Because strict semver doesn't include the `v`. Either strip it before matching (`s.replace(/^v/, '')`) or change the regex to start with `^v?`.
Does this compare versions?
No, it only validates the format. Use a semver library for comparison — semver precedence rules are subtle (especially around pre-release identifiers and build metadata being ignored).
Can I use this in a CI tag check?
Yes — combined with `^v?`, this is what GitHub Actions, GoReleaser, and most CI release workflows use to validate version tags.