Why large integers lose precision
Bottom line: Integers above 2^53-1 lose precision in JSON.parse. Snowflake IDs, order numbers and database bigints all hit this, so keep them as strings end to end.

Bottom line: treat snowflake IDs, order numbers and bigint primary keys as strings through serialization, transport and parsing; keep the numeric type only when the field is proven to stay within 2^53-1, and then enforce it with a maximum constraint in the Schema.
Because the damage happens during parsing, silently.
JSON.parse('{"id": 9007199254740993}');
// { id: 9007199254740992 }
The missing digit is gone; there is nothing to recover.
Where 2^53 comes from
JavaScript has one numeric type: IEEE 754 double precision, with 53 bits of significand (one implicit, 52 explicit). Exact integers therefore stop at ±(2^53-1):
-9007199254740991 .. 9007199254740991
Above that line, consecutive representable values are 2, 4, 8 apart. 9007199254740993 is odd, and at that magnitude every representable value is even, so it rounds to 9007199254740992.
Fields that get hit
| Field | Digits | Risk |
|---|---|---|
| Snowflake IDs | 18–19 | High, last digits change |
| Order / transaction numbers | 16–20 | High |
| Database bigint primary keys | 19 | High |
| Money in minor units | — | Low |
| Millisecond timestamps | 13 | Safe |
The common thread: these are identifiers, not quantities. An identifier is transported, never added or multiplied, so string is the correct type.
Four fixes
Serialize as string. The backend converts bigint fields before writing the response. Simple and durable; document that these fields are strings.
Let the serializer handle it. Jackson's ToStringSerializer for Long, Go's json:",string" tag. Same idea: keep the value out of the numeric path.
Parse with BigInt support. json-bigint and similar libraries. Note that BigInt cannot mix with Number arithmetic, and JSON.stringify rejects it.
Constrain the range. If the field genuinely cannot exceed 2^53, add maximum in the Schema so out-of-range data fails validation instead of failing silently in the browser.
How to tell whether you have this bug
Take a known ID and round-trip it: serialize, transmit, parse, compare character by character. Or inspect the raw response body — an unquoted 19-digit number that arrives with the wrong last digits is almost certainly a parse-time loss.
FAQ
Why does JSON.parse change the last digits without an error?
JavaScript has one numeric type, IEEE 754 double precision, so integers above 2^53-1 can only land on the nearest representable value. JSON.parse treats that as a normal numeric conversion: it neither throws nor warns.
How can the frontend keep big integers intact?
Use a library such as json-bigint, because JSON.parse cannot do it. The cost is that BigInt cannot mix with Number arithmetic and JSON.stringify rejects it, so the surrounding code has to change too.
Should the API docs state that these fields are strings?
Yes. Serializing to strings is the simplest and most durable fix, but it only works if consumers treat the value as text, so the field type has to be written into the API contract.