rust-ksuid

A pure-Rust, fully tested implementation of KSUIDs — K-sortable, globally unique identifiers compatible with Segment's original KSUID spec.

Library
Cargo
v0.10.0
122stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
65/100Good
Development Activity80
Maintenance56
Community48
Maturity56
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
78/100Good
Architecture82
Code Quality85
Innovation55
Learning Curve90

svix-ksuid is a small, dependency-light Rust crate for generating and working with KSUIDs (K-Sortable Unique IDs) — 20-byte identifiers that embed a timestamp alongside random payload bytes, so IDs sort roughly by creation time even without a central coordinator. It is byte-for-byte compatible with Segment’s original Go implementation, so IDs generated by either library interoperate freely across services written in different languages.

The crate exposes two variants behind a single KsuidLike trait: the standard Ksuid type with one-second timestamp accuracy, and KsuidMs, which trades one byte of random payload for roughly 4ms accuracy while remaining a valid, interchangeable KSUID. Both support base62 string encoding/decoding, raw byte access, and total ordering out of the box, and the crate is generic over the timestamp type — pulling in time, chrono, or jiff as optional feature flags, or falling back to std::time::SystemTime with zero extra dependencies. An optional serde feature adds transparent serialize/deserialize support.

What You Get

  • Ksuid — the standard KSUID variant with one-second timestamp accuracy, matching the original Segment KSUID spec exactly
  • KsuidMs — a millisecond-accuracy (~4ms) variant that trades one payload byte for finer time ordering, while still producing valid, interoperable KSUIDs
  • Base62 encode/decodeto_base62()/from_base62() (and Display/FromStr impls) for the standard 27-character string representation
  • Pluggable timestamp backends — feature flags for time (0.3.x), chrono (0.4.x), and jiff (0.2.x), or plain std::time::SystemTime with no extra dependencies
  • Optional serde supportSerialize/Deserialize impls for both Ksuid and KsuidMs gated behind the serde feature
  • Total orderingPartialOrd/Ord derive directly from the byte layout, so KSUIDs can be sorted or compared like any other value

Common Use Cases

  • Database primary keys that need to be both globally unique and roughly time-sortable without a central sequence generator
  • Distributed event or log IDs where approximate chronological ordering across services simplifies debugging and pagination
  • Interop with existing Segment-KSUID-based systems (e.g. services already using the Go segmentio/ksuid library)
  • Request/webhook IDs in systems (like Svix’s own webhook delivery service) that need lexically sortable identifiers exposed to API consumers
  • Any UUID-replacement use case where sort order by creation time is a nice-to-have property

Under The Hood

Architecture The crate centers on a single KsuidLike trait implemented by two concrete 20-byte tuple structs, Ksuid and KsuidMs, defined in one file (src/lib.rs). The trait supplies shared behavior — base62 encode/decode, byte access, payload slicing, Display/FromStr — while each struct implements only the timestamp-specific pieces: Ksuid packs a 4-byte big-endian seconds-since-KSUID-epoch prefix, KsuidMs packs a 5-byte prefix combining seconds and a compressed 4ms-resolution sub-second component. A separate Timestamp trait abstracts over the pluggable time backends (SystemTime, time::OffsetDateTime, chrono::DateTime<Utc>, jiff::Timestamp), each implemented behind its own cfg-gated feature block, with a DefaultTimestamp type alias resolving to whichever backend is enabled. This keeps the core ID logic decoupled from any specific time library — changing the default timestamp resolution order only touches the type-alias cfg block, nothing else.

Tech Stack Pure Rust, edition 2024, minimum Rust version 1.88. Core dependencies are minimal: byteorder for big-endian integer packing, base-encode for base62 string conversion, and getrandom for payload randomness. Optional dependencies (time, chrono, jiff, serde) are all gated behind Cargo features so consumers only pay for what they use; time03 is enabled by default for backward compatibility. Build tooling is a plain cargo workflow plus a justfile for common tasks, with deny.toml configured for cargo-deny dependency auditing and a pre-commit config for formatting/linting.

Code Quality The crate ships with an extensive unit test suite inline in src/lib.rs covering timestamp round-tripping across every optional backend (SystemTime, time, chrono, jiff), plus a separate tests/integration.rs file that validates behavior against a fixture file of known KSUID test vectors (tests/test_kuids.txt) for cross-implementation compatibility. Error handling uses a small custom Error type implementing std::error::Error rather than panics for recoverable failures like malformed base62 input, though a few internal byte-copy paths do .unwrap() on invariants the type system already guarantees. CI (.github/workflows) and .pre-commit-config.yaml enforce formatting and linting on every change; typos.toml and deny.toml add spelling and dependency-policy checks.

API Design The public API is deliberately small and consistent: both ID types expose the same now(), new(), from_seconds(), from_bytes(), to_base62()/from_base62() surface via the shared trait, so switching between Ksuid and KsuidMs requires no code changes beyond the type name. Doctests embedded throughout src/lib.rs double as both documentation and executable examples, and the crate’s default feature set (time03) means use svix_ksuid::*; Ksuid::now(None) works with zero configuration for the common case, while advanced users can opt into chrono04/jiff02/serde explicitly.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search