Skip to content
Generate now

MongoDB ObjectId Structure Explained Byte by Byte

Every MongoDB document gets an _id, and unless you say otherwise it is an ObjectId such as 65a1f3c2e4b0a1b2c3d4e5f6. It looks random, but it is carefully structured: hidden inside are a timestamp, a random value and a counter. Knowing how those twelve bytes are laid out helps you debug data, sort documents, write realistic seed scripts and decide when a custom _id makes more sense.

Options

Tip: press Enter or Space to generate again.

Ready

Twelve bytes, three parts

An ObjectId is 12 bytes, written as 24 hexadecimal characters (two per byte). In current MongoDB versions the layout is:

  • Bytes 1โ€“4 (characters 1โ€“8): a timestamp โ€” seconds since the Unix epoch.
  • Bytes 5โ€“9 (characters 9โ€“18): a random value generated once per process.
  • Bytes 10โ€“12 (characters 19โ€“24): a counter that starts at a random value and increases with each new ObjectId.

Older versions used a machine identifier and process ID in the middle; the switch to a random value improved privacy and uniqueness across containers.

Reading the timestamp

Because the first eight hex characters are a timestamp, every ObjectId carries its own creation date. In the MongoDB shell, ObjectId("65a1f3c2e4b0a1b2c3d4e5f6").getTimestamp() returns the date, and most drivers offer an equivalent method. You can also decode it by hand: convert the first eight characters from hexadecimal to a decimal number and treat it as Unix seconds.

This is handy for quick debugging โ€” you can see when a document was inserted without a separate createdAt field. The precision is only one second, though, so keep a proper timestamp field when you need exact times.

Sorting and uniqueness

Since the timestamp comes first, sorting by _id roughly sorts documents by creation time, and many apps paginate this way. Two caveats apply:

  • Within the same second, order depends on the random value and counter, so it is only approximate.
  • ObjectIds created on different machines depend on each machineโ€™s clock, so small clock differences can shuffle the order.

Uniqueness comes from the combination of all three parts: the timestamp separates seconds, the random value separates processes and the counter separates IDs made by one process in the same second.

How to create ObjectIds with the generator

Seed scripts, JSON fixtures and API tests often need IDs that MongoDB will accept. The generator above follows the official layout:

  1. Choose how many ObjectIds you need โ€” up to 200 per batch.
  2. Generate them and notice the pattern: IDs from one batch share the same timestamp prefix, and consecutive IDs often differ only in the last characters as the counter increases.
  3. Paste them into seed files, for example as {"$oid": "โ€ฆ"} values in Extended JSON, or into test requests that reference documents.
  4. Export the list as CSV, JSON or TXT for reuse.

Everything is created in your browser; nothing is sent to a database.

When to use your own _id

The _id field can hold any unique value, not only an ObjectId. A natural key such as an ISBN, a UUID shared with another system, or a short slug can be a better fit when it is truly unique and never changes. Stick with ObjectId when you have no such key: it is compact, generated by the driver without a round trip to the server and already indexed.

Querying by date with _id

Because the timestamp sits at the front, you can find documents created in a time window without a separate date field. Build an ObjectId whose first eight characters encode the start time and whose remaining characters are zeros, do the same for the end time, and query for _id values between them. The default index on _id makes this fast.

This trick is great for exploring data and for one-off maintenance scripts. For application features such as reports, a dedicated, indexed date field is clearer and more precise.

Pro tips

  • Use the embedded timestamp for debugging, but keep a createdAt field for business logic.
  • Validate that incoming IDs are exactly 24 hex characters before querying.
  • Avoid exposing ObjectIds publicly if creation times should stay private.
  • Keep ObjectIds lowercase in fixtures to match what drivers usually print.

Frequently asked questions

Can two ObjectIds ever be the same?

It is extremely unlikely. A duplicate would need the same second, the same random process value and the same counter value.

Can I create an ObjectId for a past date?

Most drivers can build an ObjectId from a given timestamp, which is useful for range queries on _id by date.

Is an ObjectId the same as a UUID?

No. An ObjectId is 12 bytes with a defined timestamp and counter, while a UUID is 16 bytes and comes in several versions.

Try a generator

Random Address Generator

Realistic street addresses with valid-format postal codes and phone numbers for 40 countries.

Fake Identity Generator

Complete fictional person profiles: name, birthday, address, phone, email, job and more.

Need random data? Get it now.

Pick any of 144 generators, hit Generate and copy or export the results as CSV, JSON or TXT. No account, no limits, nothing stored.

Start generating โ€” free