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.
Using This Generator
The generator runs in the browser. Each ULID is built from the browser clock and 80 fresh random bits taken from the browser's cryptographic random number generator, so no identifier is sent to or fetched from a server.
- Number of ULIDs accepts a whole number from 1 to 50. The default is 1.
- Generate ULID produces a new batch. Changing the count also produces a new batch.
- Copy on a result copies that single ULID. When more than one is shown, Copy all copies the whole list, one ULID per line.
- Reset sets the count back to 1 and generates one new ULID.
Under the results, the ULID Structure panel splits the first ULID in the batch into its two parts: the first 10 characters (the timestamp) and the last 16 (the randomness).
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.