You probably do not need UUIDs
In systems, everything is fine until the software needs to work on more than one node. The simple and convenient auto-incrementing ID suddenly becomes a bottleneck. What if two users tweet at the same time? How do we solve for this?

# The distributed problem
In systems, everything is fine until the software needs to work on more than one node. The simple and convenient auto-incrementing ID suddenly becomes a bottleneck. What if two users tweet at the same time? How do we solve for this? How do we ensure that the tweet id is unique across machines? There are several ways to do this but I’ll compare just two. The first one is the UUID.
# The UUID
A UUID (Universally Unique Identifier) is a 128-bit number used to uniquely identify data in computer systems. Expressed as 36 alphanumeric characters (e.g., 123e4567-e89b-12d3-a456-426614174000), they are decentralised and guarantee global uniqueness without a central registry.
What this means, two users can tweet in at the same time, the tweets land on different nodes but they’ll be unique.
# However
Everything has trade offs. For one, they occupy a much larger space compared to numerical IDs. Most IDs fit in u32 (unsigned 32 bit integer). This is significantly smaller than what the 126bit uuids occupy.
The indexing is also so much slower with uuids as compared to numerical ids.
Before you Ackhtually me?

I know. I’m aware of UUIDv7 which includes a timestamp field to aid with sorting. I also know that there is a concern about enumeration attacks where someone might guess the next data based on the current ID. All valid but I still think UUIDs are an overkill.
# So what should you try instead?
I’m glad you asked. Or did. Whatever… Allow me to introduce you to Snowflake IDS.
# Snowflake IDs
The main reason UUIDs are great in distributed systems is the fact that they reduce the chances of primary key collision to zero. Imagine you have two restaurants. Each with their own local databases in order to reduce latency and ensure internet outages do not disrupt operations. The data is essentially local first then synced later. With auto incrementing IDs, both databases will definitely generate the same primary key and syncing will be broken. UUIDs fix this easily.
But they feel like cargo culting to me. I always ask questions and so far, I’m not sold on UUIDs.
—
# The snowflake
Snowflakes allows the keys to be sequential but unique. To achieve this, we break it down into sections. This is how it works.
A snowflake is an unsigned 64 bit integer. It contains the following parts:
- Sign Bit (1 bit): Always 0 to keep the ID as a positive number.
- Timestamp (41 bits): The time in milliseconds since a specific start date (or “epoch”). For Twitter, that is November 4, 2010, at 01:42:54 UTC
- Machine/Worker ID (10 bits): Identifies the specific server that created the ID.
- Sequence Number (12 bits): Starts at 0 and counts up for each ID created in the same millisecond by the same server. It resets every millisecond.
Just like that, you have a B-tree friendly performant primary key for your database.
# Who uses this?
Twitter is the original creator. Not the current Twitter the pre-Elon one. So next time, you see a tweet id, you are looking at a snowflake id. From this you can get all kinds of information like the machine, and the time the tweet was sent. The latter feels pointless because timestamp columns exist but it is a good thing to know and brag about.
Here is a sample Rust program that you can use on Rust playground to get information about a tweet id.
use std::time::{Duration, UNIX_EPOCH};
// Twitter's official Snowflake Epoch: November 4, 2010, 01:42:54.657 UTC
const TWITTER_EPOCH_MS: u64 = 1_288_834_974_657;
#[derive(Debug)]
pub struct DecodedSnowflake {
pub timestamp_ms: u64,
pub machine_id: u64,
pub sequence: u64,
}
pub fn decode_twitter_id(snowflake_id: u64) -> DecodedSnowflake {
// 1. Right-shift 22 bits to remove the 10-bit machine ID and 12-bit sequence
let offset_ms = snowflake_id >> 22;
// 2. Add Twitter's custom epoch value to get absolute Unix time
let timestamp_ms = offset_ms + TWITTER_EPOCH_MS;
// 3. Extract the machine ID (bits 12 to 21) using a 10-bit mask (0x3FF)
let machine_id = (snowflake_id >> 12) & 0x3FF;
// 4. Extract the sequence number (last 12 bits) using a 12-bit mask (0xFFF)
let sequence = snowflake_id & 0xFFF;
DecodedSnowflake {
timestamp_ms,
machine_id,
sequence,
}
}
fn main() {
// Example: A real historical Wikipedia Tweet ID from February 2025
let tweet_id: u64 = 1_888_944_671_579_078_978;
let decoded = decode_twitter_id(tweet_id);
// Convert Unix millisecond timestamp into a human-readable format
let d = UNIX_EPOCH + Duration::from_millis(decoded.timestamp_ms);
let datetime: chrono::DateTime<chrono::Utc> = d.into();
println!("Decoded Twitter Snowflake:");
println!("├─ Exact Time: {}", datetime.to_rfc3339());
println!("├─ Machine ID: {}", decoded.machine_id);
println!("└─ Sequence ID: {}", decoded.sequence);
}
Other places that use UUIDs include Discord and Instagram. At discord, it handles all those millions of messages a day. Not convinced yet? Well, at Sony, it powers the PSN.
Thank you for reading. Happy coding.