ESC

Type to search the knowledge base.

BigInt Basics

BigInt for integers beyond Number.MAX_SAFE_INTEGER — literals, ops, JSON gaps, and when Number is still the right tool.

intermediate3 min read
  • javascript
  • bigint
  • numbers

Number is IEEE-754 double. Integers are only safe up to 2^53 - 1 (Number.MAX_SAFE_INTEGER). Past that, IDs and counters silently round. BigInt is arbitrary-precision integers — for snowflake IDs, cryptography-ish counters, and anything that must stay exact.

Creating BigInts

const a = 9007199254740993n; // literal — suffix n
const b = BigInt('9007199254740993');
const c = BigInt(42);

Number.isSafeInteger(9007199254740993); // false — already rounded as Number
9007199254740993n === BigInt('9007199254740993'); // true

Prefer BigInt('...') for values that came from JSON/strings. BigInt(1.5) throws; only integers convert.

Arithmetic

10n + 20n; // 30n
10n * 3n;  // 30n
10n / 3n;  // 3n  — truncates toward zero
10n % 3n;  // 1n
2n ** 10n; // 1024n

// mixed types throw
// 1n + 1 → TypeError
1n + BigInt(1); // 2n
Number(1n) + 1; // 2 — but may lose precision for large values

Comparisons between Number and BigInt work; arithmetic does not:

1n < 2;   // true
1n == 1;  // true
1n === 1; // false

When frontends need it

// Twitter/Snowflake-style IDs as strings in JSON, as BigInt in logic
function idGreater(a, b) {
  return BigInt(a) > BigInt(b);
}

idGreater('9007199254740993', '9007199254740992'); // true
// Number compare would already be wrong for these

Bitwise ops work on BigInt (& | ^ ~ << >>), which is handy for flag packs that exceed 32 bits (Number bitwise ops coerce to int32).

JSON and the ecosystem

JSON.stringify({ id: 1n }); // TypeError: Do not know how to serialize a BigInt

JSON.stringify({ id: 1n }, (_, v) =>
  typeof v === 'bigint' ? v.toString() : v,
);
// {"id":"1"}

JSON.parse('{"id":"1"}', (key, value) =>
  key === 'id' ? BigInt(value) : value,
);

APIs almost always send large IDs as strings. Keep them strings at the boundary; convert to BigInt only when you need math or ordered compare.

TypedArray and many Web APIs still speak Number. Check support before you invent BigInt pipelines through canvas or WebGL.

Division and signs

(-10n) / 3n; // -3n
(-10n) % 3n; // -1n

No >>> for BigInt. Unary + is not allowed on BigInt (+1n is a syntax error in some contexts — use BigInt or just the literal).

Footguns

Trap Fix
Mixing Number math Explicit convert both sides
JSON.stringify Replacer → string
Math.* helpers Don’t work on BigInt; use your own
Performance BigInt is slower than Number; don’t use for animation frames
parseInt on big strings Loses precision; use BigInt(str)

Interview answer

“BigInt holds integers of arbitrary size with an n suffix. You can’t mix them with Number in arithmetic without converting. JSON doesn’t serialize them, so wire formats use strings. I use BigInt for large IDs and exact integer math; Number remains correct for UI measurements and anything under MAX_SAFE_INTEGER.”

Mixed comparisons and sorting

const ids = [10n, 2n, 100n];
ids.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
// cannot use a - b — subtraction works, but subtracting Number breaks; keep BigInt-only

// coerce for display only
function formatId(id) {
  return typeof id === 'bigint' ? id.toString() : String(id);
}

Typed arrays and DataView still speak Number for most widths; BigInt64Array / BigUint64Array exist when you need 64-bit integer buffers. Don’t cast large snowflake IDs through Number “just for sorting” — you reintroduce the precision bug you adopted BigInt to fix.

Further reading

Related guides