Click on an ID to copy.
| Property | Value |
|---|---|
| Bit Length | 128 |
| Output Length | 25 chars |
| Encoding | base36 |
| Sortable | Yes |
| Timestamped | Yes |
| Monotonic | Yes |
| Crypto Random | Yes |
SCRU128 (Sortable, Clock-and-Random-based Unique Identifier with 128-bit length) is a modern unique identifier format designed as a successor to both ULID and UUID, addressing shortcomings in earlier time-sortable ID schemes. Created by LiosK, SCRU128 was motivated by the observation that while ULID and KSUID brought significant improvements over random UUIDs, they still had gaps in monotonicity guarantees and clock rollback handling. SCRU128 was engineered to provide strict monotonic ordering within a single generator, graceful handling of clock anomalies, and a compact textual representation within the same 128-bit space as a UUID. The result is an identifier that combines the best properties of its predecessors while solving edge cases that cause subtle bugs in distributed systems.
The format represents each 128-bit identifier as a 25-character Base36 string composed of digits and lowercase letters. This encoding is case-insensitive, meaning applications can normalize SCRU128 values to uppercase or lowercase without affecting equality or sort order. At 25 characters, a SCRU128 string is more compact than a standard UUID (36 characters with hyphens) and comparable to a ULID (26 characters), while preserving the full 128 bits of information that makes it compatible with UUID-sized storage columns in databases like PostgreSQL, MySQL, and SQL Server.
The 128-bit structure of a SCRU128 ID is divided into four carefully designed fields that work together to ensure global uniqueness, chronological sorting, and strict monotonicity.
The first field occupies the most significant 48 bits and stores a millisecond-precision Unix timestamp. With 48 bits of timestamp space, SCRU128 can represent dates from the Unix epoch all the way to approximately the year 10889, providing far more range than the 32-bit second-resolution timestamps used by formats like KSUID (which are limited without custom epochs). This timestamp field drives the primary sort order: identifiers generated at different milliseconds will always sort chronologically.
The remaining 80 bits are distributed across three layers of random and counter data, which is the defining innovation of SCRU128. The first layer is a 24-bit counter that increments each time a new ID is generated within the same millisecond on the same generator. This counter ensures that up to 16.7 million IDs generated in a single millisecond will maintain strict monotonic ordering. The second layer is a 24-bit per-generation entropy field that is refreshed with new random data when the counter overflows or when the millisecond advances, providing additional uniqueness between generator restarts and counter resets. The third layer is a 32-bit random field that is drawn from a cryptographically secure source for every ID generated, ensuring global uniqueness across independent generators that have no knowledge of each other.
This three-layer approach solves a problem inherent in ULID's design. ULID specifies that the random portion should be monotonically incremented within the same millisecond, but the specification does not precisely define how overflow or clock rollbacks should be handled. SCRU128's explicit counter, per-generation entropy, and per-ID randomness create a system where monotonicity is guaranteed, overflow is handled gracefully, and clock anomalies (such as NTP corrections) do not produce out-of-order or duplicate identifiers. When the system clock moves backward, the generator continues incrementing from its last known state.
The generation algorithm is straightforward: read the current millisecond timestamp, increment the counter if the timestamp matches the previous generation, or reset the counter with fresh entropy if the timestamp has advanced. If the counter overflows, the generator advances the stored timestamp by one millisecond and resets. In all cases, the 32-bit random field is filled with new cryptographic randomness. This protocol ensures the output sequence is always strictly increasing, regardless of clock behavior or generation rate.
High-throughput event sourcing systems. Event sourcing architectures rely on event identifiers to establish a total ordering of all state changes. SCRU128's guaranteed monotonicity within a single generator means that events produced by one service instance will always be correctly ordered without relying on database-assigned sequence numbers. The 128-bit size also ensures that event IDs are globally unique across all service instances, making it safe to merge event streams from independent generators.
Distributed database primary keys. When using SCRU128 as a primary key in distributed databases, the time-sorted nature minimizes B-tree page splits and index fragmentation compared to random UUIDs. The 128-bit size is directly compatible with UUID columns, so teams can adopt SCRU128 without schema changes. The compact 25-character text representation is also easier for developers to read, copy, and communicate in logs and debugging sessions than a 36-character UUID.
Microservices request tracing and correlation. In microservices architectures, assigning a SCRU128 identifier to each incoming request provides both a unique correlation ID for distributed tracing and an embedded timestamp that indicates when the request was initiated. Unlike random UUIDs, SCRU128 correlation IDs can be sorted chronologically in log analysis tools, making it straightforward to reconstruct the timeline of a distributed operation.
IoT device telemetry and sensor data. Internet of Things deployments often involve thousands of devices independently generating data records. SCRU128 allows each device to produce globally unique, time-ordered identifiers without connectivity to a central coordination service. The three-layer randomness structure ensures that devices with imprecise or drifting clocks will not produce colliding identifiers, and the monotonic guarantee within each device preserves the correct ordering of its readings.
SCRU128 and ULID share the same 128-bit size and the concept of combining a millisecond timestamp with randomness for sortable, unique identifiers. The critical difference is in monotonicity handling. ULID's specification calls for incrementing the random portion within the same millisecond, but implementations vary in how they handle overflow and clock rollback. SCRU128 formalizes this with its three-layer structure and explicit counter, providing deterministic behavior in all edge cases. SCRU128's Base36 encoding produces a 25-character case-insensitive string versus ULID's 26-character Crockford base32 string. If your system relies on strict monotonicity guarantees, SCRU128 is the more rigorous choice. If broad ecosystem support is the priority, ULID has a larger community.
Compared to UUID v7, SCRU128 offers a similar value proposition with a different philosophy. UUID v7 (RFC 9562) embeds a Unix timestamp in the most significant bits of a standard 128-bit UUID, making it time-sortable while remaining compatible with UUID infrastructure. UUID v7 benefits from the massive ecosystem of UUID tooling and database support. SCRU128 is not constrained by UUID's structural requirements, allowing it to dedicate more bits to counter and entropy layers. The result is stronger monotonicity guarantees and a more compact representation (25 characters versus 36). If RFC compliance is paramount, UUID v7 is the pragmatic choice. If you prioritize ordering guarantees and compact strings, SCRU128 is stronger.
When compared to KSUID, the differences are in bit allocation and temporal precision. KSUID uses 160 bits with a 32-bit second-resolution timestamp and 128 bits of pure randomness, encoded as a 27-character base62 string. SCRU128 uses 128 bits with a 48-bit millisecond timestamp and 80 bits of structured randomness and counters. KSUID's larger random space provides a wider collision-resistance margin, but it lacks explicit monotonicity mechanisms. KSUID's second-resolution timestamp means IDs within the same second have no guaranteed ordering, whereas SCRU128 maintains strict ordering down to sub-millisecond granularity. For systems where ordering correctness matters as much as uniqueness, SCRU128 is the more appropriate format.
import { scru128String } from 'scru128';
const id = scru128String();
console.log(id);SCRU128 (Sortable, Clock-based, Realm-unique, Uniformly-distributed 128-bit) is a unique identifier specification designed to be a modern alternative to UUID. It encodes a millisecond-precision timestamp alongside random and counter components in a 128-bit value, producing IDs that are both globally unique and chronologically sortable.
SCRU128 offers higher timestamp precision (millisecond vs. ULID's millisecond with less overall entropy) and a built-in monotonic counter that strictly guarantees ordering even within the same millisecond. Unlike ULID, SCRU128 is a full 128-bit format that fits natively into UUID-sized database columns without any compatibility issues.
Yes, SCRU128 guarantees strict monotonic ordering within a single generator instance. Each successive ID is guaranteed to be greater than the previous one, even when multiple IDs are generated within the same millisecond. This is achieved through an internal counter that increments for same-timestamp generations.
A SCRU128 ID is represented as a 25-character string using base36 encoding, which consists of lowercase letters and digits. The underlying binary format is 128 bits (16 bytes), making it compatible with UUID-sized storage columns in databases while providing a more compact and readable text representation.
SCRU128 provides time-based sorting, monotonic ordering, and higher entropy than UUID v4, all within the same 128-bit size. Unlike random UUIDs, SCRU128 IDs can be used as efficient database primary keys because their sequential nature reduces index fragmentation and enables time-range queries without an additional timestamp column.
Timeflake is a 128-bit, roughly-ordered, URL-safe UUID combining a 48-bit millisecond timestamp with 80 bits of cryptographic randomness.
TSID (Time-Sorted ID) is a compact, time-sortable identifier inspired by Snowflake and ULID, producing 13-character Crockford base32 strings.
ULID (Universally Unique Lexicographically Sortable Identifier) is a type of identifier designed to be both globally unique and sortable in a lexicographically manner.
UUID v7 is a time-sortable UUID defined by RFC 9562, embedding a millisecond Unix timestamp with cryptographic randomness for global uniqueness.
© 2024 Carova Labs. All rights reserved