jsguides

BigInt

BigInt is a built-in object that represents arbitrary-precision integers. It allows you to work with integers larger than the safe integer limit (Number.MAX_SAFE_INTEGER, which is 2^53 - 1).

Creating BigInt values

Create a BigInt by appending n to an integer literal, or by calling the BigInt() function:

const bigNumber = 9007199254740993n;
// 9007199254740993n

const fromString = BigInt("9007199254740993");
// 9007199254740993n

const fromNumber = BigInt(9007199254740993);
// 9007199254740993n

The BigInt() function accepts strings, numbers, and even booleans (BigInt(true) returns 1n), but passing a decimal string like "1.5" throws a RangeError. When converting from Number, be aware that values larger than Number.MAX_SAFE_INTEGER may already have lost precision before BigInt sees them, so prefer string conversion for large values.

Arithmetic operations

BigInt supports the standard arithmetic operators:

const a = 10n;
const b = 5n;

a + b    // 15n
a - b    // 5n
a * b    // 50n
a / b    // 2n
a % b    // 0n
a ** b   // 100000n (exponentiation)

Division truncates toward zero — 7n / 2n is 3n, not 3.5n. This is consistent with integer division in most languages and is the reason these operations never produce floating-point results. The exponentiation operator (**) supports large exponents, but the result grows extremely fast and can consume significant memory.

The unary minus operator works with BigInt:

-5n      // -5n

Unlike Number, where the minus operator can produce -0, BigInt has no negative zero — -0n is simply 0n. BigInt comparisons also differ from Number comparisons in important ways.

Comparison operations

BigInt values can be compared with other BigInt or Number values, including mixing types with inequality operators:

5n > 3        // true
5n === 5      // false (strict equality: different type)
5n == 5       // true (loose equality)
0n === 0n     // true

Strict equality (===) always returns false when comparing BigInt to Number because they are different primitive types, even if the numeric value is the same. Loose equality (==) coerces types first, so 5n == 5 is true. For readable code, avoid relying on loose equality between BigInt and Number — convert explicitly instead. When comparing values of the same type, both strict and loose equality behave identically, so there is no ambiguity with two BigInts or two Numbers.

Use BigInt.asUintN() and BigInt.asIntN() to clamp values to a specific bit width:

BigInt.asUintN(8, 300n)   // 44n (300 mod 256)
BigInt.asIntN(8, 300n)    // 44n
BigInt.asIntN(8, 130n)    // -126n (130 - 256)

These methods are useful for implementing cryptographic algorithms or protocols where you need to keep values within a specific bit range. asUintN interprets the result as unsigned, while asIntN interprets it as two’s complement signed.

Type checking

Check if a value is a BigInt using typeof:

typeof 10n   // "bigint"

The typeof operator is the only reliable way to distinguish BigInt from Number at runtime, since Object.prototype.toString.call(10n) returns "[object BigInt]" but this approach requires extra parsing. In production code, prefer typeof value === "bigint" for clarity.

Limitations

  • Cannot mix BigInt with Number in arithmetic operations
  • Cannot use Math functions with BigInt values
  • BigInt() without arguments returns 0n

Practical examples

Working with large numbers

Factorials are a classic use case because results exceed Number.MAX_SAFE_INTEGER quickly. The recursive approach below works because BigInt supports the same operators and control flow as Number:

// Calculate factorial of 50
function factorial(n) {
  if (n <= 1n) return 1n;
  return n * factorial(n - 1n);
}

const result = factorial(50n);
// 30414093201713378043612608166064768844377641568960512000000000000n

Recursive factorial is straightforward with this type, but for very large inputs the call stack may overflow. An iterative version avoids that risk and is simpler to reason about for computation-heavy tasks. For smaller utility functions, the recursive form reads clearly and maps directly to the mathematical definition, so choose based on the expected input range.

Bitwise operations

const value = 15n;

value >> 2n   // 3n
value << 2n   // 60n
(value | 1n)  // 15n (already odd)

BigInt bitwise operators work the same way as Number bitwise operators but without the 32-bit truncation — they are treated as having infinite sign-extended bits, so shifts and masks behave correctly on arbitrary-size integers.

Mixing BigInt with number types

You cannot use arithmetic operators between BigInt and Number values directly — doing so throws a TypeError. You must explicitly convert one type to the other. Converting a large BigInt to Number can lose precision if the value exceeds Number.MAX_SAFE_INTEGER.

5n + 5;          // TypeError: Cannot mix BigInt and other types
5n + BigInt(5);  // 10n — explicit conversion
Number(5n) + 5;  // 10  — converts BigInt to Number

The explicit conversion rule is a deliberate design choice. JavaScript does not silently coerce between BigInt and Number in arithmetic because doing so would risk silent precision loss. This is different from the loose equality operator (==), which does perform coercion for comparison.

String conversion

BigInt values convert to strings without the trailing n:

String(123n); // '123'
`${456n}`;    // '456'

JSON.stringify() throws on BigInt values. To serialise a BigInt, call .toString() first or provide a replacer function.

Browser support

BigInt is available in all modern browsers and Node.js 10.3+. It is not supported in Internet Explorer.

BigInt and JSON

JSON.stringify() throws a TypeError if the value being serialized contains a BigInt. This is intentional — the JSON specification has no BigInt type, and silently converting to a number would lose precision. To serialize BigInt values, convert them to strings first: use bigintValue.toString() before passing to JSON.stringify(), and parse them back from strings after JSON.parse().

Comparison with Number

BigInt values can be compared to Number values with <, >, <=, >=, and == (loose equality), but not === (strict equality). 42n == 42 is true because loose equality coerces types; 42n === 42 is always false because they are different types. For sorting purposes, this means you can freely mix BigInt and Number in comparison expressions, but you should be deliberate about which type you are working with to avoid unintentional coercions.

See also