Copy any ID in Discord (a user, a server, a message, anything) and you get a long number like 175928847299117063. That number is a snowflake: a 64-bit unique identifier that Discord assigns to every object on the platform. It is not random. Packed inside those digits are the exact creation time of the object, an identifier for the machine that generated it, and a sequence counter.
Snowflakes are the kind of infrastructure detail most users never notice, but they are worth understanding. They explain why Discord IDs can be decoded into creation dates, why the IDs keep getting longer over the years, and how Discord mints billions of unique IDs across thousands of machines without ever producing a duplicate.
The Short Definition
A Discord snowflake is a 64-bit unsigned integer, written out in decimal as a number 17 to 19 digits long. Every user, server (guild), channel, message, role, emoji, webhook, and attachment on Discord has one, and no two objects ever share an ID.
The defining feature is that most of the bits store a timestamp. That makes snowflakes chronologically sortable: if one ID is numerically larger than another, it was created later. This single property does a lot of quiet work across Discord's API, from message ordering to pagination.
Discord did not invent the scheme. Twitter designed it in 2010, when it needed a way to generate unique tweet IDs across many machines at once, and released the design as an open source project called Snowflake. Discord adopted the format with its own epoch, and variants of the same idea run inside Instagram and plenty of other large-scale systems.
The Bit Layout
Here is the complete anatomy of a Discord snowflake:
| Field | Bits | Size | What it stores |
|---|---|---|---|
| Timestamp | 63 to 22 | 42 bits | Milliseconds since the Discord epoch |
| Worker ID | 21 to 17 | 5 bits | Which internal worker generated the ID |
| Process ID | 16 to 12 | 5 bits | Which process on that worker generated it |
| Increment | 11 to 0 | 12 bits | A per-process counter that increases with every ID generated |
The timestamp: bits 63 to 22
Forty-two bits of every snowflake count the milliseconds elapsed since Discord's chosen zero point. Forty-two bits of milliseconds is roughly 139 years of range, so the format will not run out until well into the 22nd century.
This is the practically useful field. Extract it, add the Discord epoch, and you know the exact moment the object was created. It is how our snowflake converter turns any Discord ID into a creation date, and it is the basis of tricks like checking when an account was created.
Worker ID and process ID: bits 21 to 17 and 16 to 12
Five bits each, so values from 0 to 31. These identify which of Discord's internal ID-generation workers, and which process on that worker, produced the snowflake. They tell you nothing useful from the outside, but they are essential to the design: two machines generating IDs in the same millisecond produce different worker bits, so the resulting IDs still differ.
The increment: bits 11 to 0
A 12-bit counter (0 to 4095) that ticks up for every ID a process generates, then rolls over. If a single process mints two IDs within the same millisecond, the increment keeps them distinct.
Between the three non-timestamp fields, a single millisecond can in theory yield over four million unique IDs (32 workers times 32 processes times 4096 increments) with zero collisions.
The Discord Epoch
Unix timestamps count milliseconds from January 1, 1970. Discord snowflake timestamps count from a later zero point: 1420070400000 milliseconds after the Unix epoch, which is 2015-01-01T00:00:00.000 UTC, the start of the year Discord launched.
Why not just use 1970? Bit budget. Starting the clock 45 years later keeps timestamps comfortably inside 42 bits for far longer. This is a common pattern: Twitter's original snowflakes used a 2010 epoch for exactly the same reason.
Converting a snowflake timestamp into a normal date is therefore a two-step operation: take the top 42 bits, then add 1420070400000 to get a standard Unix millisecond timestamp. From there, any date library, or our unix timestamp converter, can format it however you like.
Decoding a Snowflake in JavaScript
The whole decode fits in a few lines:
const id = "175928847299117063"; // example ID from Discord's API docs
const DISCORD_EPOCH = 1420070400000n;
const unixMs = (BigInt(id) >> 22n) + DISCORD_EPOCH;
console.log(new Date(Number(unixMs)).toISOString());
// 2016-04-30T11:18:25.796Z
One detail that bites people constantly: you cannot parse a snowflake as a regular JavaScript number. Number.MAX_SAFE_INTEGER is 9007199254740991, which is 16 digits, and snowflakes run 17 to 19 digits. parseInt or Number() will silently corrupt the low bits, destroying the worker, process, and increment fields and potentially shifting the timestamp. Keep IDs as strings, and convert with BigInt when you need to do math.
The other three fields come out with shifts and masks:
const workerId = (BigInt(id) >> 17n) & 31n; // bits 21 to 17
const processId = (BigInt(id) >> 12n) & 31n; // bits 16 to 12
const increment = BigInt(id) & 4095n; // bits 11 to 0
For the example ID above, that yields worker ID 1, process ID 0, and increment 7, matching the worked example in Discord's own API documentation.
Why Design IDs This Way?
Snowflakes solve two problems that hit every large distributed system.
Unique IDs without a central authority
The naive way to hand out unique IDs is a single database with an auto-incrementing counter. That works until it becomes both a bottleneck and a single point of failure, because every object created anywhere in the system has to wait in line at one counter. Twitter hit exactly this wall in 2010 while moving tweets off a single database, and Snowflake was its answer.
With snowflakes, any worker on any machine can mint IDs entirely on its own. The combination of timestamp, worker ID, process ID, and increment guarantees global uniqueness with no coordination at all: no locks, no network round-trips, no shared counter.
Sortable by time, for free
Because the timestamp occupies the most significant bits, sorting snowflakes numerically sorts them chronologically. Discord's API leans on this constantly. Message history queries take before and after parameters that are just message IDs, and ordering messages by ID is the same as ordering them by send time.
There is a neat practical consequence for developers: you can construct a synthetic snowflake for any moment in time with (unixMs - 1420070400000) << 22 and use it as a pagination boundary, even though no real object carries that exact ID.
Where You'll See Snowflakes
Every one of these is a snowflake, and all of them decode the same way:
- User IDs, including bot accounts
- Server IDs (called guild IDs in the API)
- Channel IDs, covering text channels, voice channels, threads, and DMs
- Message IDs
- Role, emoji, sticker, webhook, and attachment IDs
A regular Discord message link contains three of them at once: discord.com/channels/<server ID>/<channel ID>/<message ID>. Once you know that, message links become little bundles of decodable metadata.
Snowflakes vs UUIDs
Developers sometimes ask why Discord did not just use UUIDs, the other standard answer to distributed unique IDs. The comparison is instructive.
A random UUID (version 4) also needs no coordination between machines, but it costs 128 bits instead of 64, it does not sort by creation time, and it carries no readable information. A snowflake is half the size, indexes beautifully in databases precisely because new IDs are always numerically larger than old ones, and doubles as a creation timestamp. The trade-off is that snowflakes leak that timestamp to anyone who looks, and they require loosely synchronized clocks plus assigned worker IDs on the generating machines.
For a chat platform where messages must be ordered by time anyway, and where creation dates are not secret, the snowflake side of that trade is an easy win. That is why the format spread from Twitter to Discord, Instagram, and beyond.
Quick Answers
Why are some IDs 17 digits and others 19?
The timestamp grows over time, so newer snowflakes are numerically bigger. IDs created in 2015 and 2016 are typically 17 digits, while recent ones are 19. The length alone gives you a rough era before you even decode the number.
Are snowflake IDs private or sensitive?
No. They are public identifiers, visible to anyone who shares a server with the object, and they reveal nothing beyond the creation timestamp. No account details, no activity, and nothing personal is encoded in them.
Can a snowflake ever change?
Never. IDs are assigned once at creation and stay fixed for the life of the object, and effectively beyond it: if you keep an ID after the object is deleted, the timestamp still decodes correctly.
Is the format documented?
Yes. Discord documents the snowflake structure, the epoch, and the worked example used above in its official API reference, which is why the decoding math above is safe to build on.
Try It
Paste any Discord ID into our free snowflake converter. It decodes all four fields (timestamp, worker ID, process ID, and increment) and shows the exact creation date in your local timezone. Grab your own user ID, your server's ID, or any message ID and see what is inside the number.