Skip to main content
Bun provides a fast semver (semantic versioning) parser and comparator for working with version strings. It follows the Semver 2.0.0 specification.

Basic Usage

import { semver } from "bun";

// Parse version
const version = semver.parse("1.2.3");
console.log(version); // { major: 1, minor: 2, patch: 3 }

// Compare versions
console.log(semver.satisfies("1.2.3", "^1.0.0")); // true
console.log(semver.satisfies("2.0.0", "^1.0.0")); // false

Version Parsing

Basic Versions

import { semver } from "bun";

// Major.minor.patch
const v1 = semver.parse("1.2.3");
console.log(v1.major, v1.minor, v1.patch); // 1 2 3

// With v prefix
const v2 = semver.parse("v2.0.0");
console.log(v2.major); // 2

Prerelease Versions

// Alpha, beta, rc
const alpha = semver.parse("1.0.0-alpha");
const beta = semver.parse("1.0.0-beta.1");
const rc = semver.parse("2.0.0-rc.1");

console.log(alpha.prerelease); // "alpha"
console.log(beta.prerelease); // "beta.1"

Build Metadata

const version = semver.parse("1.0.0+20230615");
console.log(version.build); // "20230615"

// Both prerelease and build
const full = semver.parse("1.0.0-beta.1+exp.sha.5114f85");
console.log(full.prerelease); // "beta.1"
console.log(full.build); // "exp.sha.5114f85"

Version Comparison

Order Comparison

import { semver } from "bun";

// Greater than
console.log(semver.order("2.0.0", "1.0.0")); // 1

// Less than
console.log(semver.order("1.0.0", "2.0.0")); // -1

// Equal
console.log(semver.order("1.0.0", "1.0.0")); // 0

Comparison Functions

import { semver } from "bun";

console.log(semver.gt("2.0.0", "1.0.0")); // true (greater than)
console.log(semver.gte("2.0.0", "2.0.0")); // true (greater than or equal)
console.log(semver.lt("1.0.0", "2.0.0")); // true (less than)
console.log(semver.lte("1.0.0", "1.0.0")); // true (less than or equal)
console.log(semver.eq("1.0.0", "1.0.0")); // true (equal)
console.log(semver.neq("1.0.0", "2.0.0")); // true (not equal)

Version Ranges

Caret Ranges (^)

Allows changes that don’t modify the left-most non-zero digit:
import { semver } from "bun";

// ^1.2.3 := >=1.2.3 <2.0.0
console.log(semver.satisfies("1.2.3", "^1.2.3")); // true
console.log(semver.satisfies("1.3.0", "^1.2.3")); // true
console.log(semver.satisfies("2.0.0", "^1.2.3")); // false

// ^0.2.3 := >=0.2.3 <0.3.0
console.log(semver.satisfies("0.2.3", "^0.2.3")); // true
console.log(semver.satisfies("0.2.4", "^0.2.3")); // true
console.log(semver.satisfies("0.3.0", "^0.2.3")); // false

// ^0.0.3 := >=0.0.3 <0.0.4
console.log(semver.satisfies("0.0.3", "^0.0.3")); // true
console.log(semver.satisfies("0.0.4", "^0.0.3")); // false

Tilde Ranges (~)

Allows patch-level changes:
import { semver } from "bun";

// ~1.2.3 := >=1.2.3 <1.3.0
console.log(semver.satisfies("1.2.3", "~1.2.3")); // true
console.log(semver.satisfies("1.2.4", "~1.2.3")); // true
console.log(semver.satisfies("1.3.0", "~1.2.3")); // false

// ~1.2 := >=1.2.0 <1.3.0
console.log(semver.satisfies("1.2.0", "~1.2")); // true
console.log(semver.satisfies("1.2.9", "~1.2")); // true

// ~1 := >=1.0.0 <2.0.0
console.log(semver.satisfies("1.0.0", "~1")); // true
console.log(semver.satisfies("1.9.9", "~1")); // true

Wildcard Ranges (x, X, *)

import { semver } from "bun";

// * := >=0.0.0 (any version)
console.log(semver.satisfies("1.2.3", "*")); // true

// 1.x := >=1.0.0 <2.0.0
console.log(semver.satisfies("1.2.3", "1.x")); // true
console.log(semver.satisfies("2.0.0", "1.x")); // false

// 1.2.x := >=1.2.0 <1.3.0
console.log(semver.satisfies("1.2.3", "1.2.x")); // true
console.log(semver.satisfies("1.3.0", "1.2.x")); // false

Comparison Operators

import { semver } from "bun";

// Greater than
console.log(semver.satisfies("2.0.0", ">1.0.0")); // true

// Greater than or equal
console.log(semver.satisfies("1.0.0", ">=1.0.0")); // true

// Less than
console.log(semver.satisfies("1.0.0", "<2.0.0")); // true

// Less than or equal
console.log(semver.satisfies("1.0.0", "<=1.0.0")); // true

// Equal
console.log(semver.satisfies("1.0.0", "=1.0.0")); // true

Range Combinations

import { semver } from "bun";

// AND (space or &&)
console.log(semver.satisfies("1.2.3", ">=1.0.0 <2.0.0")); // true
console.log(semver.satisfies("1.2.3", ">=1.0.0 && <2.0.0")); // true

// OR (||)
console.log(semver.satisfies("1.0.0", "1.x || 2.x")); // true
console.log(semver.satisfies("2.0.0", "1.x || 2.x")); // true
console.log(semver.satisfies("3.0.0", "1.x || 2.x")); // false

Hyphen Ranges

import { semver } from "bun";

// 1.2.3 - 2.3.4 := >=1.2.3 <=2.3.4
console.log(semver.satisfies("1.2.3", "1.2.3 - 2.3.4")); // true
console.log(semver.satisfies("2.0.0", "1.2.3 - 2.3.4")); // true
console.log(semver.satisfies("2.3.4", "1.2.3 - 2.3.4")); // true
console.log(semver.satisfies("2.3.5", "1.2.3 - 2.3.4")); // false

Prerelease Versions

Prerelease Precedence

import { semver } from "bun";

// Prerelease versions are lower than release versions
console.log(semver.lt("1.0.0-alpha", "1.0.0")); // true

// Prerelease identifiers are compared lexically
console.log(semver.lt("1.0.0-alpha", "1.0.0-beta")); // true
console.log(semver.lt("1.0.0-beta", "1.0.0-rc")); // true

// Numeric identifiers are compared numerically
console.log(semver.lt("1.0.0-alpha.1", "1.0.0-alpha.2")); // true
console.log(semver.lt("1.0.0-alpha.9", "1.0.0-alpha.10")); // true

Prerelease Ranges

import { semver } from "bun";

// Prerelease versions only match if explicitly included
console.log(semver.satisfies("1.0.0-alpha", "1.0.0")); // false
console.log(semver.satisfies("1.0.0-alpha", ">=1.0.0-alpha")); // true

// Range must include prerelease
console.log(semver.satisfies("1.0.0-beta", "^1.0.0-alpha")); // true
console.log(semver.satisfies("1.0.0-beta", "^1.0.0")); // false

Common Use Cases

Package Version Checking

import { semver } from "bun";

function checkDependency(installed: string, required: string): boolean {
  return semver.satisfies(installed, required);
}

console.log(checkDependency("2.1.0", "^2.0.0")); // true
console.log(checkDependency("1.9.0", "^2.0.0")); // false

Finding Latest Version

import { semver } from "bun";

function findLatest(versions: string[]): string {
  return versions.sort((a, b) => semver.order(b, a))[0];
}

const versions = ["1.0.0", "2.1.0", "1.5.0", "2.0.0"];
console.log(findLatest(versions)); // "2.1.0"

Version Compatibility

import { semver } from "bun";

function isCompatible(
  version: string,
  minVersion: string,
  maxVersion: string,
): boolean {
  return (
    semver.gte(version, minVersion) &&
    semver.lte(version, maxVersion)
  );
}

console.log(isCompatible("1.5.0", "1.0.0", "2.0.0")); // true
console.log(isCompatible("2.1.0", "1.0.0", "2.0.0")); // false

Breaking Change Detection

import { semver } from "bun";

function hasBreakingChange(from: string, to: string): boolean {
  const v1 = semver.parse(from);
  const v2 = semver.parse(to);
  
  return v2.major > v1.major;
}

console.log(hasBreakingChange("1.5.0", "2.0.0")); // true
console.log(hasBreakingChange("1.5.0", "1.6.0")); // false

Increment Version

import { semver } from "bun";

function increment(
  version: string,
  type: "major" | "minor" | "patch",
): string {
  const v = semver.parse(version);
  
  switch (type) {
    case "major":
      return `${v.major + 1}.0.0`;
    case "minor":
      return `${v.major}.${v.minor + 1}.0`;
    case "patch":
      return `${v.major}.${v.minor}.${v.patch + 1}`;
  }
}

console.log(increment("1.2.3", "major")); // "2.0.0"
console.log(increment("1.2.3", "minor")); // "1.3.0"
console.log(increment("1.2.3", "patch")); // "1.2.4"

Performance

Bun’s semver is highly optimized:
import { semver } from "bun";

const start = performance.now();
for (let i = 0; i < 100_000; i++) {
  semver.satisfies("1.2.3", "^1.0.0");
}
console.log(`${performance.now() - start}ms`);
// Typically <50ms for 100k checks
Comparison:
  • Bun semver: ~2M ops/sec
  • node-semver: ~500k ops/sec

Best Practices

  1. Use caret for libraries
    // Allow compatible updates
    semver.satisfies(version, "^1.2.3");
    
  2. Use exact versions for apps
    // Lock to specific version
    semver.satisfies(version, "1.2.3");
    
  3. Be careful with prereleases
    // Explicitly handle prereleases
    if (version.includes("-")) {
      console.warn("Prerelease version");
    }
    
  4. Validate versions
    try {
      semver.parse(version);
    } catch {
      console.error("Invalid version");
    }
    

API Reference

semver.parse()

Parse a version string:
semver.parse(version: string): {
  major: number;
  minor: number;
  patch: number;
  prerelease?: string;
  build?: string;
}

semver.satisfies()

Check if version satisfies range:
semver.satisfies(version: string, range: string): boolean

semver.order()

Compare two versions:
semver.order(a: string, b: string): -1 | 0 | 1

Comparison Functions

semver.gt(a: string, b: string): boolean   // greater than
semver.gte(a: string, b: string): boolean  // greater than or equal
semver.lt(a: string, b: string): boolean   // less than
semver.lte(a: string, b: string): boolean  // less than or equal
semver.eq(a: string, b: string): boolean   // equal
semver.neq(a: string, b: string): boolean  // not equal

Build docs developers (and LLMs) love