JavaScript Bigint: Complete Guide

BigInt is JavaScript's primitive for arbitrarily large integers. Learn to create BigInts, perform operations, handle mixed-type rules, and use BigInt for precise math beyond Number's limits.

6 min read

A BigInt is a numeric primitive in JavaScript that can represent integers of any size. The standard Number type maxes out at 9,007,199,254,740,991 (Number.MAX_SAFE_INTEGER), and beyond that, integer precision breaks down.

BigInt has no such limit.

javascriptjavascript
const maxSafe = Number.MAX_SAFE_INTEGER;
console.log(maxSafe);      // 9007199254740991
console.log(maxSafe + 1);  // 9007199254740992 (OK)
console.log(maxSafe + 2);  // 9007199254740992 (WRONG -- same as +1!)
 
// BigInt handles this correctly
const bigSafe = 9007199254740991n;
console.log(bigSafe + 1n); // 9007199254740992n
console.log(bigSafe + 2n); // 9007199254740993n (correct!)

The n suffix marks a BigInt literal. Without it, the value is a regular Number and subject to the same precision limits.

Creating BigInts

JavaScript gives you two ways to create a BigInt, and which one you reach for depends on whether the value is known while you are writing the code or only becomes available at runtime:

javascriptjavascript
// Literal with n suffix -- for values known at authoring time
const a = 42n;
const b = -10n;
 
// Constructor -- for values computed or parsed at runtime
const c = BigInt(42);
const d = BigInt("9007199254740993"); // From a string
const e = BigInt(true);               // 1n
const f = BigInt(false);              // 0n
 
console.log(a, b, c, d, e, f);
// 42n, -10n, 42n, 9007199254740993n, 1n, 0n

Use the n suffix for literals. Use BigInt() when converting from a Number, a string, or a boolean. Passing a decimal string or a non-integer Number throws a RangeError:

javascriptjavascript
BigInt(3.14);       // RangeError
BigInt("3.14");     // SyntaxError
BigInt("not a number"); // SyntaxError

Only integers can become BigInts. No fractions, no decimals.

Arithmetic with BigInts

BigInt supports the standard arithmetic operators, and they behave the same way you would expect from regular integer math, with one exception around division covered right after this example:

javascriptjavascript
const x = 100n;
const y = 3n;
 
console.log(x + y);  // 103n -- addition
console.log(x - y);  // 97n  -- subtraction
console.log(x * y);  // 300n -- multiplication
console.log(x / y);  // 33n  -- division (truncates toward zero!)
console.log(x % y);  // 1n   -- remainder
console.log(x ** y); // 1000000n -- exponentiation

Division truncates toward zero. 100n divided by 3n is 33n, not 33.333, because there are no fractional BigInts at all. If you need the quotient and remainder together, a small helper function can compute both at once:

javascriptjavascript
function divmod(a, b) {
  return { quotient: a / b, remainder: a % b };
}
 
console.log(divmod(100n, 3n)); // { quotient: 33n, remainder: 1n }

The Hard Rule: No Mixing with Number

You cannot mix BigInt and Number in the same operation. This is one of the strictest rules in the language, and JavaScript enforces it at runtime rather than silently converting one side for you:

javascriptjavascript
const big = 10n;
const num = 5;
 
big + num; // TypeError: Cannot mix BigInt and other types

This is by design. Adding a BigInt and a Number creates an ambiguity: should the result be a BigInt, losing the fractional part of the Number, or a Number, losing the precision of the BigInt?

The language refuses to guess. You must convert explicitly:

javascriptjavascript
const big = 10n;
const num = 5;
 
// Explicit conversion -- you choose which type
console.log(big + BigInt(num));  // 15n
console.log(Number(big) + num);  // 15 (loses precision if BigInt is huge)

Convert to BigInt when you need exact integer results. Convert to Number only when you are certain the BigInt fits safely within Number's safe integer range.

Comparisons

Comparison operators work across BigInt and Number, but strict equality does not:

javascriptjavascript
console.log(1n == 1);   // true  -- loose equality coerces
console.log(1n === 1);  // false -- different types
 
console.log(1n < 2);    // true
console.log(2n > 1);    // true
console.log(1n < 1);    // false
console.log(1n <= 1);   // true

Use loose equality for cross-type checks when you only care about the mathematical value. Use strict equality when you need to distinguish BigInt from Number.

ComparisonBetween 1n and 1Why
Loose equalitytrueLoose equality coerces both sides to the same numeric value
Strict equalityfalseStrict equality also checks the type, and BigInt and Number are different types
Relational (less than, greater than, etc.)Work normallyThese operators compare mathematical value, not type

BigInt and Math Methods

The Math object does not accept BigInts. Calling Math.abs on a BigInt throws a TypeError. This is because Math methods operate on Numbers and return Numbers, and silent conversion would lose precision:

javascriptjavascript
// Math.abs(-5n); // TypeError
 
// Instead, write your own for BigInts when needed
function bigAbs(n) {
  return n < 0n ? -n : n;
}
 
console.log(bigAbs(-5n)); // 5n

JSON and BigInt

JSON.stringify throws on BigInt because the JSON format has no BigInt type of its own. This is a common surprise the first time an ID field happens to hold a BigInt value:

javascriptjavascript
const data = { id: 9007199254740993n, name: "Alex" };
 
// JSON.stringify(data); // TypeError: Do not know how to serialize a BigInt

The fix is a custom toJSON() method on the object, or a replacer function passed to JSON.stringify that handles every BigInt regardless of where it appears:

javascriptjavascript
// Option 1: toJSON on the object
const data = {
  id: 9007199254740993n,
  name: "Alex",
  toJSON() {
    return { id: this.id.toString(), name: this.name };
  }
};
console.log(JSON.stringify(data)); // {"id":"9007199254740993","name":"Alex"}
 
// Option 2: replacer function (works for any BigInt anywhere)
function bigintReplacer(key, value) {
  if (typeof value === "bigint") return value.toString();
  return value;
}
console.log(JSON.stringify({ id: 1n }, bigintReplacer)); // {"id":"1"}

To parse those strings back into real BigInt values on the way in, pass a reviver function as the second argument to JSON.parse:

javascriptjavascript
const json = '{"id":"9007199254740993","name":"Alex"}';
 
const parsed = JSON.parse(json, (key, value) => {
  if (key === "id") return BigInt(value);
  return value;
});
 
console.log(parsed.id); // 9007199254740993n

Practical Use Case: Unique IDs

Many systems generate IDs larger than MAX_SAFE_INTEGER. Twitter Snowflake IDs and some database auto-increment values routinely exceed 9 quadrillion:

javascriptjavascript
// A Snowflake-style ID from an API response
const rawId = "18285738472829337600";
const id = BigInt(rawId);
 
console.log(id);                     // 18285738472829337600n
console.log(Number(rawId));          // 18285738472829338000 (wrong last 3 digits!)
 
// BigInt preserves every digit
console.log(id.toString());          // "18285738472829337600"

If you store this ID as a Number, the last few digits are lost. If you later query by that truncated ID, the query fails silently, since the database has no row matching the rounded value. BigInt avoids this entire class of bug by preserving the exact digits from the moment the value enters your code.

Practical Use Case: Timestamp Arithmetic at Nanosecond Precision

When working with high-resolution timestamps, summing many values can overflow Number precision long before it overflows the value range, since Number silently loses integer accuracy well before it runs out of digits:

javascriptjavascript
// High-resolution timestamps (performance.now() returns fractional ms)
// A BigInt-based accumulator avoids precision drift
let totalNs = 0n;
 
function addMeasurement(startNs, endNs) {
  totalNs += (endNs - startNs);
}
 
addMeasurement(1000000001n, 1000000050n);
addMeasurement(2000000001n, 2000000100n);
 
console.log(totalNs); // 148n

BigInt Limits and Gotchas

GotchaExplanation
No fractional results5n / 2n is 2n, not 2.5n. Use a library if you need arbitrary-precision decimals.
No unary plus+5n throws a TypeError. Use BigInt() or stick with the literal.
No unsigned right shiftBigInts are signed and arbitrarily large, so unsigned right shift has no defined meaning.
No Math methodsMath.max(1n, 2n) throws. Write your own helper.
parseInt and parseFloat return NumberUse BigInt() or a string approach for large values.

BigInt is a specialized tool. For everyday math, Number is faster and more convenient, and /javascript/javascript-number-type-complete-guide covers the standard numeric type in full.

Reach for BigInt when you see values larger than 9 quadrillion or when you need a guarantee of exact integer results. For serializing BigInt values, review the JSON handling patterns in /javascript/json-parse-and-json-stringify-in-javascript-guide.

Rune AI

Rune AI

Key Insights

  • BigInt is a primitive type for integers of any size, created with an n suffix (42n) or BigInt(value).
  • BigInt supports +, -, *, /, **, and % but cannot be mixed with Number in the same operation.
  • Division with BigInt truncates toward zero (no fractional results).
  • Use BigInt for values beyond Number.MAX_SAFE_INTEGER (9,007,199,254,740,991).
  • JSON.stringify does not support BigInt. Use toJSON() or a replacer to serialize as strings.
RunePowered by Rune AI

Frequently Asked Questions

When should I use BigInt instead of Number?

Use BigInt when you need to represent integers larger than Number.MAX_SAFE_INTEGER (9 quadrillion) without losing precision, or when you need exact integer math for cryptography, financial calculations, or unique IDs. For most everyday arithmetic, Number is sufficient and faster.

Why can't I mix BigInt and Number in operations?

The language designers chose to forbid implicit mixing because it would introduce silent precision loss. If you add a BigInt and a Number, which type should the result be? Either choice could lose information. You must explicitly convert one side.

Conclusion

BigInt fills the gap that Number left open for integer precision. When you need to work with IDs larger than 9 quadrillion, perform exact financial calculations without floating-point rounding, or handle cryptographic values, BigInt gives you arbitrary-precision integers as a first-class primitive. The mixed-type restrictions are deliberate and protect you from silent precision bugs. Convert explicitly, and BigInt delivers exactly the value you expect.