[READ-ONLY] Mirror of https://github.com/sxzz/verkit. Fast, zero-dependency SemVer for ESM and TypeScript, with functional, tree-shakeable APIs.
esm functional immutable range semantic-versioning semver typescript version
TypeScript 100%
JavaScript <1%

README.md

verkit #

Open on npmx npm downloads Unit Test Codecov

Fast, zero-dependency SemVer for ESM and TypeScript, with functional, tree-shakeable APIs.

Features #

  • ✅ Complete SemVer version and range toolkit.
  • 🚀 Faster than node-semver across tested operations.
  • 📦 Pure ESM with zero runtime dependencies.
  • 💙 First-class TypeScript declarations.
  • 🌳 Functional, tree-shakeable named exports.
  • 🔁 Mutable SemVer and SemVerRange records.
  • ⚡ 26.0% smaller for full CDN imports.
  • 🪶 61.4% smaller with common bundled imports.
  • 🛡️ Immutable collection operations.

Install #

npm add verkit

Versions #

import {
  coerce,
  increment,
  normalize,
  normalizeFull,
  parse,
  truncate,
} from 'verkit'

const version = parse('1.2.3-rc.1+sha.abc')
const coerced = coerce('release 42.6.7.9', { rtl: true })
version.patch = 4

normalizeFull(version) // '1.2.4-rc.1+sha.abc'
normalize(version) // '1.2.4-rc.1'
increment(version, 'minor') // '1.3.0'
truncate(version, 'patch') // '1.2.4'
coerced?.major // 6

Version APIs accept strings or mutable SemVer objects returned by parse or coerce. normalizeFull keeps build metadata; normalized, incremented, and truncated versions omit it.

Comparison #

import { compare, compareBuild, isGreaterThan, sortReversed } from 'verkit'

compare('1.0.0+one', '1.0.0+two') // 0
compareBuild('1.0.0+one', '1.0.0+two') // -1
isGreaterThan('2.0.0', '1.0.0') // true
sortReversed(['1.0.0', '2.0.0']) // ['2.0.0', '1.0.0']

compare ignores build metadata; compareBuild uses it as a tie-breaker.

Ranges #

import {
  findMaxSatisfying,
  normalizeRange,
  parseRange,
  satisfies,
} from 'verkit'

const range = parseRange('^1.2.3')

normalizeRange(range) // '>=1.2.3 <2.0.0-0'
satisfies('1.5.0', range) // true
findMaxSatisfying(['1.2.3', '1.5.0', '2.0.0'], range) // '1.5.0'

Range APIs accept strings or mutable SemVerRange objects. They support comparators, unions, hyphens, wildcards, tilde, caret, loose parsing, and prereleases.

Range options are fixed when a SemVerRange is created. APIs that receive a parsed range use its stored options and do not accept another options argument:

const prereleases = parseRange('1.x', { includePrerelease: true })

satisfies('1.0.0-rc.1', prereleases) // true

To use different options, pass the original range string again or create another parsed range.

API #

See the API reference.

Invalid input behavior #

parse, parseComparator, and parseRange throw detailed TypeErrors. Their tryParse* wrappers return null; other safe transforms and predicates keep their documented null/false behavior.

Migrating from node-semver #

Only renamed or reshaped node-semver APIs are listed; same-named functions such as clean, coerce, compare, and satisfies are omitted.

node-semver verkit
SemVer parse
parse tryParse
valid normalize
inc, diff increment, difference
major, minor, patch, prerelease getMajor, getMinor, getPatch, getPrerelease
rcompare, compareLoose, cmp compareReversed, compare with { loose: true }, compareWithOperator
eq, neq, gt, gte, lt, lte isEqual, isNotEqual, isGreaterThan, isGreaterThanOrEqual, isLessThan, isLessThanOrEqual
rsort sortReversed
rcompareIdentifiers compareIdentifiersReversed
Comparator SemVerComparator, parseComparator, tryParseComparator
Comparator formatting, test, and intersection normalizeComparator, satisfiesComparator, comparatorsIntersect
Range parseRange
toComparators, validRange rangeToComparators, normalizeRange
maxSatisfying, minSatisfying, minVersion findMaxSatisfying, findMinSatisfying, findMinimumForRange
outside, gtr, ltr isOutsideRange, isGreaterThanRange, isLessThanRange
intersects, subset rangesIntersect, isRangeSubset
RELEASE_TYPES INCREMENT_TYPES (also includes release)

valid returns a normalized string | null in node-semver, so its equivalent is normalize. Use isValid when you only need a boolean.

Use options objects such as { loose: true } and { identifier, identifierBase }. Range options belong to the string-parsing step; parsed SemVerRange objects already contain them.

Differences from node-semver #

verkit follows node-semver semantics with four user-visible differences:

  • Array helpers never mutate their inputs.
  • Parsed SemVerRange objects retain their parse-time options. node-semver helpers may reparse a Range from raw using call-site options.
  • verkit is ESM-only, with no CommonJS, CLI, or NODE_DEBUG=semver output.
  • Error text, stack traces, and supported runtimes may differ.

Bundle size #

Full package imports, minified with Rolldown:

Package Minified gzip Brotli
verkit 18,820 B 5,914 B 5,375 B
semver 24,424 B 7,427 B 6,765 B
verkit reduction 26.0% 20.4% 20.5%

Common validation, range, comparison, increment, and coercion imports, tree-shaken and minified with Rolldown:

Package Minified gzip Brotli
verkit 9,872 B 3,401 B 3,121 B
semver 25,577 B 7,500 B 6,835 B
verkit reduction 61.4% 54.7% 54.3%

Run pnpm test:size to reproduce the comparison.

Benchmarks #

Measured on a MacBook Pro with an Apple M1 Max and 32 GB RAM. Higher is better.

Operation verkit ops/s semver ops/s Faster
Parse and normalize 3.67M 3.26M verkit 1.13×
Compare 3.09M 2.36M verkit 1.31×
Compare parsed versions 40.59M 28.62M verkit 1.42×
Increment 3.38M 2.03M verkit 1.66×
Coerce 2.77M 2.32M verkit 1.19×
Satisfy uncached ranges 148.5K 122.3K verkit 1.21×
Satisfy pre-parsed inputs 22.91M 7.20M verkit 3.18×

Range benchmarks either cycle through 1,001 inputs to avoid cache hits or parse once and reuse the resulting objects.

Run runtime benchmarks with pnpm bench.

Sponsors #

Sponsors

License #

MIT © 2026-PRESENT Kevin Deng.

Parts of the implementation and test fixtures are derived from node-semver under the ISC license; see THIRD_PARTY_NOTICES.md.