ObjectId Decoder
Decode MongoDB ObjectIds to extract the embedded timestamp, process identity, and counter.
ObjectId
ObjectId Structure
The ObjectId decoder extracts the embedded Unix timestamp and the random and counter components from a MongoDB ObjectId. Paste a 24-character hex string and the decoder returns the creation date plus the 5-byte random value (unique to the machine and process) and the 3-byte counter. Useful for reconstructing when a document was created without running a query against the database.
What a MongoDB ObjectId Contains
A MongoDB ObjectId is a 12-byte value that doubles as both a unique identifier and a timestamp. It is the default _id type for MongoDB collections, which means every document gets one automatically unless you override it. The 12 bytes are split into three sections that together guarantee uniqueness across machines, processes, and time:
- Timestamp (4 bytes, 8 hex chars): the number of seconds since the Unix epoch (January 1, 1970). Top of the ID, so newer ObjectIds always sort after older ones when compared as strings.
- Random value (5 bytes, 10 hex chars): generated once per process startup. Two MongoDB processes running on the same machine will have different random values, which prevents collisions even when their clocks are perfectly synced.
- Counter (3 bytes, 6 hex chars): starts at a random integer and increments by one for every ObjectId generated within the same second. The 24-bit range allows over 16 million IDs per process per second before wrapping.
The format used to include a separate machine identifier and process ID (versions before MongoDB 3.4), but the modern format combines them into a single 5-byte random value. The decoder handles the current format - if you have a very old ObjectId from a legacy database, the embedded values still decode cleanly because only the meaning of the random bytes has changed.
How the Decoder Works
Paste a 24-character hex string into the input. The decoder parses the first 8 hex characters as a Unix timestamp in seconds, converts that to a readable date and ISO 8601 string, and reports the random and counter bytes as separate values. Anything other than 24 hex characters is rejected with a clear error so you can spot a malformed paste immediately.
- Unix Timestamp: the 4-byte timestamp parsed as seconds since 1970.
- Full Date and Time: the readable date in your browser's local timezone.
- ISO 8601: the standardized international format, useful for logs.
- Relative Time: how long ago the ObjectId was created (or how far in the future for impossibly recent values).
- Random Value: the 10-hex random bytes assigned to the generating process.
- Counter: the 6-hex counter value at the moment of generation.
If you need to decode other ID formats that also embed a creation timestamp, see the Snowflake decoder (Discord, Twitter, Instagram), the UUID decoder (UUID v1, v6, v7), or the ULID decoder. For converting the raw Unix timestamp on its own to a date, the main timestamp converter is faster.
When to Decode an ObjectId
The most common reason is "when was this document created?" without having to write a query. Typical scenarios:
- Database forensics: sort a list of documents by ObjectId and reconstruct the order they were inserted, even without a createdAt field.
- Production debugging: match an ObjectId from a stack trace or error log to the moment the document was created, narrowing down the timeline of an incident.
- Anti-fraud and moderation: identify accounts or records created in suspicious bursts by checking the embedded timestamps of a list of ObjectIds.
- API auditing: verify that newly created documents have ObjectIds matching expected creation times - a stale timestamp indicates clock drift on the writing node.
- Spotting backfills: ObjectIds backfilled from a migration script have timestamps clustered around the migration run, while organically created records spread evenly over time.
For comparing two ObjectId creation times to compute a gap, decode both and pass the resulting dates to the date difference calculator. To shift a date by a known duration (for example "is this within 30 days of the document creation time?"), use the date add/subtract calculator.
Why MongoDB Built the Timestamp In
Combining the ID and the creation timestamp in one value has real practical benefits at scale. Sorting documents by _id automatically sorts them by creation time without needing an extra index. Range queries by _id can be used as a proxy for "give me all documents created between these two timestamps" - faster than maintaining a separate createdAt index for the same purpose. The timestamp is stored once instead of twice, saving storage and write overhead.
The trade-off is that the timestamp resolution is only one second. Multiple ObjectIds generated in the same second by the same process differ only in the counter, and ObjectIds generated by different processes in the same second differ in the random bytes. For sub-second ordering, MongoDB recommends adding an explicit createdAt field with millisecond resolution rather than relying on the ObjectId alone.
Frequently Asked Questions
A MongoDB ObjectId is a 12-byte unique identifier that MongoDB assigns to every document as the default _id field unless you override it. Three sections make up the value: a 4-byte Unix timestamp, a 5-byte random value unique per process, and a 3-byte counter. Together they guarantee uniqueness across machines and time without coordination between writers.
Copy the _id of the document (the 24-character hex string) and paste it into the decoder. The Full Date and Time row in the result shows the exact moment the document was created. This works without any database query because the timestamp is embedded directly in the _id value. The resolution is one second, which is enough for almost all use cases.
The timestamp portion is 4 bytes (32 bits), counted in whole seconds since the Unix epoch. That gives one-second resolution and a range up to year 2106 before the timestamp field overflows. Multiple ObjectIds in the same second differ in the counter and random portions, but they share an identical timestamp value. For sub-second ordering add an explicit createdAt field with millisecond resolution.
Yes. The timestamp occupies the top 4 bytes, so sorting ObjectIds as 12-byte values (or as 24-character hex strings) automatically sorts them by creation time. This is why MongoDB queries that use _id for pagination work efficiently. Two ObjectIds generated in the same second on different processes are not strictly time-ordered between them, but the result is still consistent and deterministic.
The 5-byte random value is generated once when a MongoDB process starts and stays the same for the lifetime of that process. It identifies which process generated the ObjectId without needing a coordinated machine ID assignment. Two processes on the same host produce different random values because they generate the random bytes independently. The decoder reports the value as hex bytes for inspection.
The counter is a 3-byte (24-bit) integer that starts at a random value when the process starts and increments by one for every ObjectId generated. It guarantees uniqueness between IDs generated in the same second on the same process. The 24-bit range allows over 16 million IDs per process per second before wrapping, which is far higher than any realistic insert rate.
The current 4+5+3 byte layout has been stable since MongoDB 3.4 (released in 2016) and is documented in the BSON specification. Earlier versions used a different breakdown (4-byte timestamp + 3-byte machine ID + 2-byte process ID + 3-byte counter), but the total length and timestamp position are unchanged. Decoding still works correctly because only the meaning of the random portion changed.
The 32-bit unsigned timestamp field can hold values up to year 2106 (Unix timestamp 4294967295). After that the field rolls over to zero and new ObjectIds will appear to predate older ones. By 2106 MongoDB will almost certainly have introduced a new ID format, but the current format is good for another 80+ years without any change needed.
Yes, but use it only as a query boundary, not as a real document _id. MongoDB drivers expose ObjectId.createFromTime(unixTimestamp) (or new ObjectId(timestamp) in older versions), which returns an ObjectId with the given timestamp and zeroed random/counter bytes. The result is useful in queries like {_id: {$gte: ObjectId.createFromTime(...)}} to fetch documents created after a specific moment, but should not be inserted as a real document ID.
Usually yes, but not always. The ObjectId timestamp is the moment the _id was generated, which for application-driven inserts is the same as the document creation time. However, if the application sets a custom createdAt timestamp (for example, backfilling historical data) the two values will differ. Use the embedded ObjectId timestamp as a reliable lower bound for when the document actually entered the database.