Formatsemver regex

Semantic version regex

The official semver.org reference regex — major.minor.patch with optional pre-release and build metadata.

Pattern
/^(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.3

    Plain stable release.

  • 0.0.1

    Zero-major, zero-minor, patch only.

  • 2.0.0-alpha.1

    Pre-release with dot-separated identifiers.

  • 2.0.0-rc.1+build.42

    Pre-release plus build metadata.

  • 1.2.3+build

    Build metadata without a pre-release.

Does not match

  • 1.2

    Missing patch component.

  • 1.2.3.4

    Four components is not valid semver.

  • v1.2.3

    Leading `v` is convention, not semver — strip it first.

  • 01.2.3

    Leading 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.

Related patterns