Pattern library / Validation
SemVer 2.0.0 Regex
Semantic Versioning 2.0.0 has one precise shape: MAJOR.MINOR.PATCH with no leading zeros, an optional dot-separated pre-release (-beta.1) and optional build metadata (+build.5). This is the spec-faithful pattern — long, but it rejects everything the spec rejects.
^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-((0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*)(\.(0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*))*))?(\+[0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*)?$Load this pattern into the tester →
How the pattern works
- Each number is
(0|[1-9][0-9]*)— no leading zeros, per spec (01.1.1is invalid). - Pre-release identifiers alternate numeric (no leading zeros) and alphanumeric —
alpha,1,beta.11all pass;01does not. - Build metadata (
+…) allows almost anything alphanumeric with hyphens/dots — it never affects precedence, so the spec is loose there. - Most CI version checks only need the core:
^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$is the lazy 90% version.
Test it: match & no-match examples
Every row is loaded straight into the tester — click Try to see the match live:
| Input | Result | Why | |
|---|---|---|---|
2.1.4 | Match | plain release | Try → |
1.0.0-beta.1 | Match | pre-release | Try → |
10.20.30+build.42 | Match | build metadata | Try → |
1.0.0-rc.1+exp.sha.5114f85 | Match | both suffixes | Try → |
01.1.1 | No match | leading zero in major | Try → |
1.2 | No match | PATCH required | Try → |
1.2.3- | No match | empty pre-release | Try → |
Where to use it
JavaScript (package.json guard)
const SEMVER = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$/;
SEMVER.test('2.1.4-beta.1+build.5'); // true
Bash (CI gate)
VERSION="1.4.2" [[ $VERSION =~ ^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]] && echo ok || echo bad
Python
import re SEMVER = r'^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$' bool(re.fullmatch(SEMVER, '1.0.0-rc.1'))
Common mistakes
- The loose \d+\.\d+\.\d+ accepts 01.02.03 — invalid SemVer that some registries reject.
- Pre-release and metadata order is fixed: -beta.1+build, never +build- beta.
- npm sometimes ships versions like 1.0.0-0 (numeric prerelease) — covered by the alternation.
FAQ
Why is the SemVer regex so long?
Because the spec forbids leading zeros in numeric identifiers and distinguishes numeric from alphanumeric pre-release identifiers. The short version (\d+\.\d+\.\d+) is fine for display, not for validation.
How do I match only the core x.y.z part?
Use ^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ and drop both optional suffix groups.
Is this pattern valid RE2 (GA4, BigQuery, Go)?
Yes — groups, alternation and quantifiers only, no lookaround or backreferences.
Related patterns
UUID Regex — Match Any UUID (1-5) Format · Regex to Match Date (YYYY-MM-DD) — Test & Copy · Slug Regex — Match lowercase-hyphen URL Slugs
For GA4-specific patterns, see the GA4 regex cheat sheet, the page path regex guide, the event filter regex guide, the GA4 regex match types, the custom channel grouping guide and RE2 vs PCRE. Browse the full regex pattern library.