Universally Unique Lexicographically Sortable Identifier
Kotlin implementation of ULID with multiplatform support.
UUID can be suboptimal for many use-cases because:
- It isn't the most character efficient way of encoding 128 bits of randomness
- UUID v1/v2 is impractical in many environments, as it requires access to a unique, stable MAC address
- UUID v3/v5 requires a unique seed and produces randomly distributed IDs, which can cause fragmentation in many data structures
- UUID v4 provides no other information than randomness which can cause fragmentation in many data structures
Instead, herein is proposed ULID:
- 128-bit compatibility with UUID
- 1.21e+24 unique ULIDs per millisecond
- Lexicographically sortable!
- Canonically encoded as a 26 character string, as opposed to the 36 character UUID
- Uses Crockford's base32 for better efficiency and readability (5 bits per character)
- Case-insensitive
- No special characters (URL safe)
- Monotonic sort order (correctly detects and handles the same millisecond)
Add the Maven Central repository if it is not already there:
repositories {
mavenCentral()
}
Add a dependency to the dependencies block:
dependencies {
implementation "com.aallam.ulid:ulid-kotlin:$version"
}
In multiplatform projects, add a dependency to the commonMain
source set dependencies.
- Generating ULID String:
ULID.randomULID()
- Generating
ULID
instance:
val ulid = ULID.nextULID()
val ulidString = ulid.toString()
- Generating
ULID
usingULID.Factory
val factory = ULID.Factory()
val ulid = factory.nextULID()
val ulidString = ulid.toString()
The default constructor is using default kotlin.random.Random
but you can also use the ULID.Factory(Random)
builder
function to use a different Random
instance.
// generate a ULID String
val ulidString: String = ULID.randomULID()
// generate a ULID instance
val ulid: ULID = ULID.nextULID()
// generate the ByteArray for a ULID instance
val data: ByteArray = ulid.toBytes()
// generate a ULID from given ByteArray using 'fromBytes' function
val ulidFromBytes: ByteArray = ULID.fromBytes(data)
// generate a ULID from given String using 'parseULID' function
val ulidFromString: ULID = ULID.parseULID(ulidString)
// generate a ULID String from ULID instance
val ulidStringFromULID: ULID = ulid.toString()
// generate ULID instance using a monotonic factory
val ulid: ULID = ULID.Monotonic.nextULID(previousULID)
// using a monotonic factory, generate a ULID instance or null in case of overflow
val ulidStrict: ULID? = ULID.Monotonic.nextULIDStrict(previousULID)
Below is the current specification of ULID as implemented in this repository.
Timestamp
- 48 bits
- UNIX-time in milliseconds
- Won't run out of space till the year 10889 AD
Entropy
- 80 bits
- User defined entropy source.
Crockford's Base32 is used as shown. This alphabet excludes the letters I, L, O, and U to avoid confusion and abuse.
0123456789ABCDEFGHJKMNPQRSTVWXYZ
The components are encoded as 16 octets. Each component is encoded with the Most Significant Byte first (network byte order).
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 32_bit_uint_time_high |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 16_bit_uint_time_low | 16_bit_uint_random |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 32_bit_uint_random |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 32_bit_uint_random |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
01AN4Z07BY 79KA1307SR9X4MV3
|----------| |----------------|
Timestamp Entropy
10 chars 16 chars
48bits 80bits
base32 base32
ULID for Kotlin is an open-sourced software licensed under the MIT license.