semver
A fast, spec-compliant Go library for parsing, comparing, and range-matching Semantic Versioning 2.0.0 strings.
Repository Health
Technical Analysis
semver is a Go library that implements the full Semantic Versioning 2.0.0 specification for parsing, validating, comparing, and sorting version strings. It parses major.minor.patch versions along with prerelease identifiers and build metadata, exposing helper methods like GT, LT, GTE, and Compare so applications can reason about version ordering without hand-rolled string comparisons.
Beyond basic parsing, the package includes a range-matching engine that evaluates npm-style version constraints (>=1.0.0 <2.0.0, wildcards like 1.x, and OR-joined ranges), plus database/sql and encoding/json interop through Scanner/Valuer and Marshaler/Unmarshaler implementations. It has no dependencies outside the Go standard library, avoids reflection and regular expressions for performance, and is widely vendored inside larger Go tooling projects that need reliable version comparison.
What You Get
- Full SemVer 2.0.0 parsing - Parse handles major.minor.patch, prerelease identifiers, and build metadata per spec, rejecting invalid strings like leading zeroes.
- Comparison operators - Compare, GT, GTE, LT, LTE, EQ, and NE methods let you order and branch on versions without manual arithmetic.
- Range matching - ParseRange compiles npm-style range expressions (>=1.0.0 <2.0.0 || >=3.0.0, wildcards like 1.x) into a reusable matcher function.
- Standard library interop - Version implements database/sql’s Scanner/Valuer and encoding/json’s Marshaler/Unmarshaler, so it drops into structs backed by a DB column or JSON field.
- Sortable collections - The Versions type implements sort.Interface, and Sort() is a one-line helper for ordering a slice of versions.
Common Use Cases
- Enforcing a dependency’s version constraint - a package manager or plugin loader parses a declared range like ”>=1.2.0 <2.0.0” and checks whether an installed version satisfies it before allowing it to load.
- Storing app version in a database column - a service persists its own or a client’s semantic version as a string via Value()/Scan() without writing custom marshaling code.
- Gating features by version - a CLI or API compares the caller’s reported version against a minimum supported version using GTE before enabling a feature.
- Sorting release tags for changelogs - a release-automation tool parses tag names into Version structs and calls Sort() to produce a chronological ordering for changelog generation.
Under The Hood
Architecture blang/semver is organized as a single flat package (semver.go, range.go, json.go, sql.go, sort.go) rather than internal layers — appropriate for a value-type library with no runtime state. semver.go defines the core Version and PRVersion structs and the Parse/Compare logic; range.go layers a small expression parser and comparator-combinator engine (versionRange, wildcardType, ParseRange) on top of Version.Compare to evaluate npm-style range strings into a compiled Range func(Version) bool; json.go, sql.go, and sort.go each add one focused capability by implementing a standard-library interface (json.Marshaler/Unmarshaler, sql.Scanner/driver.Valuer, sort.Interface) against the same Version type. Data flows one direction — string in, validated struct out — so there is no mutable shared state, and nothing breaks downstream if internals change since callers depend only on the Version/PRVersion field layout and the documented method set.
Tech Stack The library targets Go 1.14+ (go.mod) and depends on nothing outside the standard library — strconv and strings for manual parsing (deliberately avoiding regexp and reflection per the README), errors/fmt for error construction, encoding/json and database/sql/driver for interop shims, and sort for the Versions collection type. There is no build step and no runtime dependencies to vendor; the v4/ subdirectory is a fully go-mod-compatible module carved out from the legacy root package for semantic-import-versioning compliance, and CI (Travis) additionally builds the examples/ directory and checks gofmt formatting.
Code Quality Every source file has a matching _test.go counterpart (semver_test.go, range_test.go, json_test.go, sql_test.go, sort_test.go), and the README advertises coverage tracked via Coveralls in CI, historically reported above 99%. Error handling is explicit throughout — Parse and its helpers return descriptive error values rather than panicking, with MustParse the one documented exception for callers who want panic-on-invalid-input. Naming follows idiomatic Go (exported PascalCase methods, unexported helpers like containsOnly/hasLeadingZeroes), and the type system leans on small value types (uint64 fields, an IsNum discriminator on PRVersion) rather than interfaces or generics. CI gofmt-checks the tree, though there is no modern linter configuration (golangci-lint, staticcheck) in the repo.
API Design The public API optimizes for dropping straight into idiomatic Go rather than introducing new concepts: Parse/Make/MustParse cover the strict/panic-on-error spectrum, ParseTolerant relaxes input for real-world sources like git tags (leading ‘v’, missing patch, leading zeroes), and comparisons are available both as booleans (GT/GTE/LT/LTE/EQ/NE) and a single three-way Compare for sort-style use. Rather than inventing custom interop patterns, Version implements the standard library’s own extension points — json.Marshaler/Unmarshaler, sql.Scanner/driver.Valuer, and sort.Interface via the Versions type — so it serializes, persists, and sorts using idioms Go developers already know, with essentially zero boilerplate at the call site. This isn’t algorithmically novel — it’s a conventional recursive-descent-style parser — but the developer experience is unusually polished for a small utility library.