ULID Generator - Create Sortable Unique IDs Online
Free online ULID generator that creates 26-character, lexicographically sortable unique identifiers using Crockford Base32 encoding for databases and APIs.
ULID Generator
Documentation
What Is a ULID?
A ULID (Universally Unique Lexicographically Sortable Identifier) is a 26-character code used to label records in a database or an event in a distributed system. It combines the current time with random data, so a list of ULIDs sorted alphabetically ends up sorted by the time each one was created. A ULID generator is a tool that produces these codes.
ULID Structure
A ULID has two parts, written one after the other with no separator:
- Timestamp (10 characters): the number of milliseconds since 1 January 1970 (the Unix epoch), covering up to 48 bits.
- Randomness (16 characters): 80 bits of random data, added so that two ULIDs created in the same millisecond are still almost certainly different.
Both parts are written using Crockford's Base32 alphabet: the digits 0-9 and the letters A-Z, minus the letters I, L, O, and U. Those four letters are left out because they can be mistaken for the digits 0 and 1, or for each other. The result is a string that is short, easy to read aloud, and safe to put directly in a URL.
How to Calculate a ULID
A ULID generator builds an identifier in three steps.
- Read the current time in milliseconds since the Unix epoch. This is a 48-bit number.
- Generate 80 bits of random data, normally from a cryptographically secure random number generator, giving 10 random bytes.
- Encode both parts separately using Crockford's Base32 alphabet: the 48-bit timestamp becomes 10 characters, and the 80-bit random value becomes 16 characters. The two encoded strings are joined to make the final 26-character ULID.
The encoding works by reading the number 5 bits at a time, because each Base32 character represents one of 32 possible values (2^5 = 32). Ten characters hold up to 50 bits, which is enough room for the 48-bit timestamp. Sixteen characters hold exactly 80 bits, which matches the randomness portion with nothing left over.
Worked Example
Suppose a ULID generator runs at the timestamp 1712345678901 (milliseconds since the epoch) and draws the random bytes [12, 240, 88, 3, 199, 45, 6, 231, 128, 17].
Step 1 – encode the timestamp. Divide 1712345678901 repeatedly by 32, taking the remainder each time and reading the digits from last to first (this is standard base conversion). This produces the 10-character string 01HTQW311N.
Step 2 – encode the randomness. Pack the 10 random bytes into a stream of 80 bits, then read off 5 bits at a time, converting each 5-bit chunk to a Base32 character. This produces the 16-character string 1KR5G0Y75M3EF00H.
Step 3 – join the parts. The final ULID is:
101HTQW311N 1KR5G0Y75M3EF00H
2written without the space: 01HTQW311N1KR5G0Y75M3EF00H, 26 characters in total.
ULID vs UUID
| Feature | ULID | UUID (version 4) |
|---|---|---|
| Length | 26 characters | 36 characters (with hyphens) |
| Sortable by creation time | Yes | No |
| Encoding | Crockford Base32 | Hexadecimal |
| Contains a timestamp | Yes (48 bits) | No |
| URL-safe without escaping | Yes | Yes |
Both formats aim to produce identifiers that are unique across systems without a central authority handing out numbers. The main practical difference is sorting: because a ULID starts with a timestamp, sorting ULIDs as plain text also sorts them by time. A random UUID does not have this property, since every part of it is random.
Common Uses
- Database primary keys: ULIDs let a database index new rows in roughly the order they were inserted, which many database engines handle more efficiently than fully random keys.
- Distributed systems: separate servers can each generate ULIDs independently, without coordinating with a central counter, and the results are still almost certainly unique.
- Event logs: because ULIDs sort by time, a list of event IDs can double as a rough timeline.
- API and file identifiers: the fixed 26-character, URL-safe format works cleanly in web addresses and file names.
Related identifier formats include KSUID, which also encodes a timestamp for sorting, and Snowflake IDs, used by Twitter and others, which combine a timestamp, a machine identifier, and a counter.
Code Examples
Each example below builds a ULID the same way the ULID specification describes: encode the 48-bit timestamp as 10 Crockford Base32 characters, encode 80 bits of randomness as 16 more, and join them.
JavaScript
1const ENCODING_CHARS = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
2
3function encodeULID(time, randomBytes) {
4 // Timestamp: 48 bits -> 10 characters
5 let timestampStr = '';
6 let t = time;
7 for (let i = 0; i < 10; i++) {
8 timestampStr = ENCODING_CHARS[t % 32] + timestampStr;
9 t = Math.floor(t / 32);
10 }
11
12 // Randomness: 80 bits -> 16 characters
13 let result = timestampStr;
14 let bits = 0;
15 let bitCount = 0;
16 for (let i = 0; i < 10; i++) {
17 bits = (bits << 8) | randomBytes[i];
18 bitCount += 8;
19 while (bitCount >= 5) {
20 bitCount -= 5;
21 result += ENCODING_CHARS[(bits >> bitCount) & 0x1f];
22 }
23 }
24 return result;
25}
26
27function generateULID() {
28 const randomBytes = crypto.getRandomValues(new Uint8Array(10));
29 return encodeULID(Date.now(), randomBytes);
30}
31
32console.log(generateULID());
33Python
1import os
2import time
3
4ENCODING_CHARS = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"
5
6def encode_ulid(time_ms, random_bytes):
7 # Timestamp: 48 bits -> 10 characters
8 chars = []
9 t = time_ms
10 for _ in range(10):
11 chars.append(ENCODING_CHARS[t % 32])
12 t //= 32
13 timestamp_part = "".join(reversed(chars))
14
15 # Randomness: 80 bits -> 16 characters
16 bits = 0
17 bit_count = 0
18 random_part = []
19 for byte in random_bytes:
20 bits = (bits << 8) | byte
21 bit_count += 8
22 while bit_count >= 5:
23 bit_count -= 5
24 random_part.append(ENCODING_CHARS[(bits >> bit_count) & 0x1F])
25
26 return timestamp_part + "".join(random_part)
27
28def generate_ulid():
29 return encode_ulid(int(time.time() * 1000), os.urandom(10))
30
31print(generate_ulid())
32Java
1import java.security.SecureRandom;
2import java.time.Instant;
3
4public class ULIDGenerator {
5 private static final SecureRandom random = new SecureRandom();
6 private static final char[] ENCODING_CHARS =
7 "0123456789ABCDEFGHJKMNPQRSTVWXYZ".toCharArray();
8
9 public static String generateULID() {
10 long timestamp = Instant.now().toEpochMilli();
11 byte[] randomBytes = new byte[10];
12 random.nextBytes(randomBytes);
13
14 // Timestamp: 48 bits -> 10 characters
15 char[] timestampChars = new char[10];
16 long t = timestamp;
17 for (int i = 9; i >= 0; i--) {
18 timestampChars[i] = ENCODING_CHARS[(int) (t % 32)];
19 t /= 32;
20 }
21
22 // Randomness: 80 bits -> 16 characters
23 StringBuilder result = new StringBuilder(new String(timestampChars));
24 long bits = 0;
25 int bitCount = 0;
26 for (byte b : randomBytes) {
27 bits = (bits << 8) | (b & 0xFF);
28 bitCount += 8;
29 while (bitCount >= 5) {
30 bitCount -= 5;
31 result.append(ENCODING_CHARS[(int) ((bits >> bitCount) & 0x1F)]);
32 }
33 }
34 return result.toString();
35 }
36
37 public static void main(String[] args) {
38 System.out.println(generateULID());
39 }
40}
41Frequently Asked Questions
What is a ULID used for? A ULID is used as a unique identifier for a database row, an API resource, or a logged event, in cases where sorting by creation time is also useful.
How long is a ULID? A ULID is always 26 characters long: 10 characters for the timestamp and 16 for the random part.
What encoding does a ULID use? A ULID uses Crockford's Base32 alphabet, made up of the digits 0-9 and the letters A-Z with I, L, O, and U removed to avoid confusion with other characters.
How is a ULID different from a UUID? A ULID sorts by creation time and is 26 characters long. A random (version 4) UUID does not sort by time and is 36 characters long including hyphens.
How likely is a collision between two ULIDs? The 80 bits of randomness make collisions extremely unlikely. Generating roughly 1.3 trillion ULIDs within the same millisecond would be needed to reach a 50% chance of any two matching.
Can ULIDs be generated without an internet connection? Yes. A ULID only needs the local clock and a random number generator, so it can be created entirely offline.
References
- "ULID Specification." GitHub, https://github.com/ulid/spec.
- "Crockford's Base32 Encoding." http://www.crockford.com/base32.html.