6/6/2026 at 12:43:29 AM
UUIDs are way over used. There is almost always a better key to use, usually a bigint for databases. If you're making some kind of leaderless distributed data store, then maybe, but even then there are other ID sharding strategies I'd go for first depending on the constraints.For a single database, bigints are smaller and faster, with less footguns.
UUIDs can be nice for an opaque public ID, however I'd still prefer something like a Sqid for space and usability.
by blopker
6/6/2026 at 5:31:18 PM
Providing an ID from the client is a big advantage that's missing though. Especially if you want a UI with optimistic rendering that's dealing with something asyncby Fire-Dragon-DoL
6/6/2026 at 2:39:35 AM
> bigints are smaller and faster, with less footgunsBut be careful!! Javascript WILL interpret your bigints as Number() and round them down because they are too big without telling you!!!
Famously seen by every snowflake user that has interacted with Javascript, quite an annoying problem.
by Fabricio20
6/6/2026 at 7:32:13 AM
Good trick is to prefix all such keys with magic, i.e. a couple of letters that identify type type of key.Then it will always be a string and you will be free to change the format/type of the key in the future to UUID or whatever you like.
by silvestrov
6/6/2026 at 3:43:07 PM
Rule of thumb: if you’re not doing math with a value, it’s not a number.by zmj
6/6/2026 at 10:29:30 AM
Using a Feistel cipher and base 32 encoding at the boundaries of the system can help catching vibe coded edge code that attempt to decode identifiers in javascript. It also somewhat obfuscate the cardinalities and fill rate of the tables.by Piezoid
6/6/2026 at 10:03:49 AM
This can be avoided by supplying a reviver: const json = '{ "a": 9007199254740993 }'
JSON.parse(json, (_key, value, context) => /^\d+$/.test(context.source) ? BigInt(context.source) : value)
by sheept
6/6/2026 at 2:52:21 AM
Fortunately we're seeing more JS DB libraries offering to read large numbers as the BigInt type.by spiffytech
6/6/2026 at 5:53:27 AM
But frustratingly, a JS BigInt is nothing like a BigInt in any other language.In JS - BigInt is 64bit integer.
In anything else - BigInt is a arbitrarily large integer.
by shakna
6/6/2026 at 6:02:20 AM
Hm? JavaScript BigInts are arbitrary precision, and you need to use methods like BigInt.asIntN(64, a) to convert them to 64 bitsby anematode
6/6/2026 at 7:27:57 AM
I hate this so much because you can’t nicely serialise a BigInt as JSON. Using a string is nicer but it only makes sense where int64 is used as an ID, not where it’s used as a number; and you don’t wanna have to configure this per field per query.by mort96
6/6/2026 at 10:06:18 AM
You can serialize a BigInt by specifying a replacer: const obj = { a: 9007199254740993n }
JSON.stringify(obj, (_key, value) => typeof value === 'bigint' ? JSON.rawJSON(value.toString()) : value)
by sheept
6/6/2026 at 10:27:23 AM
And then you end up with strings on the other side, not numbers.by mort96
6/6/2026 at 10:46:42 AM
No you don't? The example I gave produces {"a":9007199254740993}
not {"a":"9007199254740993"}
by sheept
6/6/2026 at 2:20:07 PM
Oh, that's much worse! The JSON string `{"a":9007199254740993}` decodes to the object `{"a":9007199254740992}` with typical JSON parsers like JavaScript's `JSON.parse`.by mort96
6/6/2026 at 8:11:26 AM
JSON has arbitrary length numbers in the spec only.by nh2
6/6/2026 at 10:26:36 AM
Completely and utterly irrelevant.by mort96
6/6/2026 at 6:50:36 AM
This is simply not true? Or maybe I misunderstand what you mean?by Etheryte
6/6/2026 at 3:10:03 AM
!!Node.js drivers will correctly read int64 as string or bigint, not number.
E.g. pg for PostgreSQL
Maybe there’s a buggy driver but I don’t know it.
by paulddraper
6/6/2026 at 5:36:39 PM
Browser!! The browser reads it as Number. If your rest api returns {"id": 1324535222364012585} for example, javascript will try and parse that as number from the response!!!You can of course, change the api such that it does {"id": "1324535222364012585"} instead and voila, it will no longer try parsing it as number. Or the many other workarounds people have recommended above (like appending a prefix, or using a different encoding), but why is it trying to parse a number thats too big and instead of throwing it just rounds down without telling you????!
by Fabricio20
6/6/2026 at 2:16:11 AM
UUIDs also have a nice benefit of it being impossible to query the wrong table with one if you mixup what an FK goes toby JamesSwift
6/6/2026 at 2:49:26 AM
Yeah this is nice - also helps with grepping dump files.by pyuser583
6/6/2026 at 4:30:02 AM
How is this done?by mamcx
6/6/2026 at 4:49:22 AM
They just mean you catch incorrect joins more easily because there is usually no overlap in keys between unrelated tables. Using int, you’re usually going to have some shared values between two unrelated tables.by nickpeterson
6/6/2026 at 4:47:11 AM
Statistically impossible to inadvertently generate a collision using UUID keys. UUID is designed to be unique when generated across any computer system. Practically speaking if you have an exactly matching pair of UUIDs from disparate system you have found the exact record match. The name gives a hint "Universally unique identifier". -Not a cryptographer.by sudoshred
6/6/2026 at 9:10:24 AM
It definitely is possible, just very improbableby usrnm
6/6/2026 at 9:35:44 AM
That’s probably what’s meant by statistically impossible.by echoangle
6/6/2026 at 4:53:42 AM
The U means if you join the wrong table your join will always come up empty.It does not actually make it impossible to query the wrong table it just tells you quickly when you’ve done so.
by masklinn
6/6/2026 at 9:54:43 AM
You can achieve this with numeric sequences too, by having a consistent step and unique offset in all your sequences. For example, if you will never exceed 16 types, reserve four bits as the type discriminant. (You don’t have to use powers of two, but it may be convenient.)All sequences use step 16.
Type A has discriminant/offset 0, yielding IDs {0, 16, 32, 48, 64, …}.
Type B has discriminant/offset 1, mapping to IDs {1, 17, 33, 49, 65, …}.
All the way up to Type P with discriminant/offset 15 and IDs {15, 31, 47, 63, 79, …}.
This is also trivially invertible so that you can determine the type from the ID.
A more common approach is to make IDs opaque strings and put a type prefix—A0, B12, P34, that kind of thing. But this way you can keep it as a number, if you wish.
by chrismorgan
6/6/2026 at 3:52:24 PM
What are uuid foot guns?by PUSH_AX
6/6/2026 at 6:51:05 AM
Yes this matters even more if you are doing a lot of joins. Naive string UUIDs are 32 bytes (though I use binary uuid in the post which is 16) compared to 8 bytes for a 64-bit int. This matters even more with sqlite as it uses varint encoding. The upshot of all this is your indexes take up a lot less space in memory.by andersmurphy
6/6/2026 at 1:18:51 AM
I am finding UUIDs help a lot if your primary schema consumer is an LLM.Inappropriate aliasing of integer keys allows for silent errors in queries because it will actually return some result a lot of the time. A UUID is immune to this problem. The model recognizes its mistake a lot more reliably when previously non-empty tables start showing up empty after attempting a join.
by bob1029
6/6/2026 at 2:36:41 AM
No one ever got fired for using UUIDsby crubier