What is ULID?
A ULID (Universally Unique Lexicographically Sortable Identifier) is a type of unique identifier designed to provide globally unique IDs that are also sortable by creation time. ULIDs were created to address the shortcomings of traditional UUIDs in terms of sorting and readability while maintaining the benefits of being decentralized and globally unique.
Key Features of ULIDs
Lexicographical Sortability:
- ULIDs are designed to be sortable based on their encoded timestamp. This makes them useful for time-series data or any application where ordering by time is important.
Compactness:
- A ULID is 128 bits in size but encoded in a 26-character string using Crockford's Base32 encoding. This makes ULIDs shorter and more readable than UUIDs.
Timestamp-based:
- The first 48 bits of a ULID represent a timestamp with millisecond precision, allowing for easy chronological sorting.
Randomness:
- The remaining 80 bits of a ULID are generated using a secure random number generator, ensuring uniqueness without a central authority.
Decentralized Generation:
- ULIDs can be generated independently on any machine without the need for coordination or a central issuing authority.
Structure of a ULID
A ULID consists of two parts:
- Timestamp: The first 48 bits (6 characters) represent the Unix timestamp in milliseconds.
- Randomness: The remaining 80 bits (16 characters) are a randomly generated value.
Example of a ULID
A ULID might look like this:
01ARZ3NDEKTSV4RRFFQ69G5FAV
- 01ARZ3: Encoded timestamp.
- NDEKTSV4RRFFQ69G5FAV: Random part ensuring uniqueness.
Use Cases for ULIDs
- Time-ordered Data: ULIDs are perfect for databases or systems where it's essential to sort records by creation time.
- Distributed Systems: Ideal for generating unique IDs in distributed systems without the need for central coordination.
- Readability: More readable and manageable than UUIDs in logs, URLs, or databases.
Generating ULIDs in Different Languages
Python
import ulid
# Generate a ULID
unique_id = ulid.new()
print(unique_id) # Output: e.g., 01ARZ3NDEKTSV4RRFFQ69G5FAV
JavaScript
const { ulid } = require('ulid');
const id = ulid();
console.log(id); // Output: e.g., 01ARZ3NDEKTSV4RRFFQ69G5FAV
Go
package main
import (
"fmt"
"github.com/oklog/ulid/v2"
"math/rand"
"time"
)
func main() {
t := time.Now().UTC()
entropy := ulid.Monotonic(rand.New(rand.NewSource(t.UnixNano())), 0)
id := ulid.MustNew(ulid.Timestamp(t), entropy)
fmt.Println(id) // Output: e.g., 01ARZ3NDEKTSV4RRFFQ69G5FAV
}
Java
import de.huxhorn.sulky.ulid.ULID;
public class Main {
public static void main(String[] args) {
ULID ulid = new ULID();
String id = ulid.nextULID();
System.out.println(id); // Output: e.g., 01ARZ3NDEKTSV4RRFFQ69G5FAV
}
}
Summary
ULIDs provide a robust solution for generating unique identifiers that are both globally unique and lexicographically sortable. With their compact size, timestamp-based ordering, and decentralization, ULIDs are suitable for a wide range of applications, especially where order and readability are essential.