Number.MAX_SAFE_INTEGER
Holds the largest integer JavaScript can represent exactly, 2^53 - 1.
Number.MAX_SAFE_INTEGER- Added in JavaScript ES2015
Return value
numberThe number 9007199254740991, that is 2^53 - 1. The property is non-writable, non-enumerable and non-configurable.
Errors
Nothing on read; assigning to it throws a TypeError in strict mode, because the property is non-writable.
JavaScript numbers are IEEE 754 doubles with a 53-bit significand, so every integer from -(2**53 - 1) through 2**53 - 1 gets a bit pattern of its own. Past that boundary the representable integers thin out — first only the even ones survive, then only multiples of four — and both arithmetic and === quietly stop agreeing with mathematics.
When to reach for it
Treat it as a boundary check, not as a number you compute with. The usual moment is when integers arrive from somewhere you do not control: database keys, snowflake-style ids, ledger totals in the smallest currency unit. Compare against it (or call Number.isSafeInteger(), which is the same test written more clearly) before you trust the value, and move to BigInt when the test fails.
What trips people up
Overflow here does not throw and does not produce Infinity. It rounds, so a wrong answer looks exactly like a right one. The literal 9007199254740993 in your source is already 9007199254740992 before the program runs — the parser rounds it. The same applies to JSON.parse(): by the time you can inspect the value, the original digits are gone.
Note also that the edge is 2**53 - 1, not 2**53. 2**53 is representable but not safe, because 2**53 + 1 is not, so two different mathematical integers collapse onto it.
Example
When to use it
- Rejecting an API id that can no longer be represented exactly before writing it to your store.
- Promoting a running total to BigInt the moment a partial sum leaves the safe range.
- Bounding a random integer generator so every value it can emit is distinct.
- Validating user-entered whole numbers in a form before they are used as identifiers.
Frequently asked questions
Why is Number.MAX_SAFE_INTEGER 2^53 - 1 and not 2^53?
Because 2^53 is representable but not safe: 2^53 + 1 rounds down onto it, so two different mathematical integers share one double. Safety requires that a value and its neighbours all have distinct representations, which stops one short of 2^53.
How do I work with integers larger than MAX_SAFE_INTEGER?
Use BigInt, written as a literal with an n suffix (9007199254740993n) or via BigInt(value). BigInt is arbitrary precision and never rounds, but it cannot be mixed with numbers in arithmetic and JSON.stringify() refuses to serialize it, so convert at the boundaries.
Does JavaScript throw an error when an integer gets too big?
No. It rounds silently to the nearest representable double, so the result is simply wrong rather than an exception. Only overflow past Number.MAX_VALUE (around 1.8e308) produces Infinity; everything between the safe limit and that point degrades quietly.
More examples
Large ids do not survive JSON.parse()
The parsed id comes back one lower than the JSON said, and comparing it to the literal 9007199254740993 reports true — because that literal rounds to the same double, so there is nothing left to compare against. isSafeInteger() is the only line that reveals the damage. Rewriting long digit runs as strings before parsing keeps the original value.
const raw = '{"id": 9007199254740993, "name": "row"}';
const parsed = JSON.parse(raw);
console.log(parsed.id); // 9007199254740992
console.log(parsed.id === 9007199254740993); // true
console.log(Number.isSafeInteger(parsed.id)); // false
// Quote the digits before parsing and they survive intact
const kept = JSON.parse(raw.replace(/:\s*(\d{16,})/g, ': "$1"'));
console.log(kept.id, typeof kept.id); // 9007199254740993 stringSwitch to BigInt when a sum leaves the safe range
The first call stays inside the safe range and returns an ordinary number. The second would overflow, so the function restarts the sum in BigInt and returns 9007199254741001n — the exact answer, with an n suffix marking it as a BigInt rather than a number.
function total(values) {
let sum = 0;
for (const v of values) {
if (!Number.isSafeInteger(sum + v)) {
return values.reduce((acc, n) => acc + BigInt(n), 0n);
}
sum += v;
}
return sum;
}
console.log(total([1, 2, 3])); // 6
console.log(total([Number.MAX_SAFE_INTEGER, 10])); // 9007199254741001n
Discussion