BigInt
Use JavaScript BigInt for exact whole-number calculations beyond Number.MAX_SAFE_INTEGER, and learn the rules for arithmetic, conversion, and fixed-width wrapping.
- 01Spot unsafe numbersUse Number.MAX_SAFE_INTEGER and Number.isSafeInteger to know when Number starts rounding whole integers.
- 02Write exact BigIntsUse the n suffix, BigInt arithmetic, and deliberate conversions without accidentally mixing types.
- 03Handle fixed-width integersExplain how BigInt.asIntN and BigInt.asUintN wrap values for 8-bit and 64-bit APIs.
BigInt in one sentence
BigInt is JavaScript’s primitive type for exact whole numbers that may be too large for Number to represent safely. A BigInt literal looks like 10n: the same digits you already know, plus an n suffix that says “keep this as an integer with as many digits as needed.”
The Data types lesson listed bigint as one of the eight built-in value types, and the Numbers & math lesson showed the warning sign: JavaScript Numbers are 64-bit floating-point values. They are excellent for everyday math, decimals, percentages, and the built-in Math tools. But when you count whole integers past Number.MAX_SAFE_INTEGER, Number starts skipping some integers. BigInt is the “do not skip a digit” tool.
Imagine a pocket calculator with a fixed display. It works quickly, but when the number gets too long, it silently rounds to fit. BigInt is more like writing digits on a strip of paper: add more paper, keep the exact integer. The trade-off is that the paper strip has no decimal point.
- In real life: A calculator display with about 16 useful digits
- In JavaScript: Number: fast and flexible, but limited integer precision
- In real life: A paper strip you can keep extending
- In JavaScript: BigInt: exact whole-number digits for as long as memory allows
- In real life: A decimal point on the calculator
- In JavaScript: Number can represent fractions like
0.5 - In real life: Only whole marks on the paper strip
- In JavaScript: BigInt has no decimal part
Where the analogy stops: BigInt is not infinite in a magical sense: memory and performance still matter. It is also not a decimal money type; it stores whole numbers only.
In this lesson you will explore the safe integer edge, write BigInt literals with the n suffix, step through exact arithmetic, fix the famous “Cannot mix BigInt and other types” error, and use BigInt.asIntN and BigInt.asUintN when an API expects a fixed number of bits.
Number.MAX_SAFE_INTEGER: the edge of safe counting
INTERACTIVEA safe integer is a Number integer that JavaScript can compare and increment reliably. The largest one is 9007199254740991, available as Number.MAX_SAFE_INTEGER. The next values are not guaranteed to behave like individual counting numbers.
Try the explorer. It prints the maximum, then steps just past it. Pay special attention to max + 1 and max + 2: Number prints the same value for both. The final line does the same addition with BigInt and stays exact.
const max = Number.MAX_SAFE_INTEGER;console.log(max);console.log(max + 1);console.log(max + 2);console.log(max + 3);console.log(2 ** 53 + 1 === 2 ** 53);console.log(Number.isSafeInteger(max + 1));console.log(BigInt(max) + 1n);9007199254740991900719925474099290071992547409929007199254740994truefalse9007199254740992n
The comparison on line 5 is true, because both Number expressions round to the same stored value.
Number says max + 1, max + 2, and max + 3 are 9007199254740992, 9007199254740992, 9007199254740994. The BigInt line for +1 is exact: 9007199254740992n.
A cheap calculator does not shout when its display is too short. It rounds. Number behaves similarly past the safe integer range: it still produces a value, but nearby integers may be missing.
- In real life: The display is full
- In JavaScript: Number has used up its precise integer digits
- In real life: The calculator rounds silently
- In JavaScript:
max + 2can collapse to the same value asmax + 1 - In real life: A warning light would be helpful
- In JavaScript:
Number.isSafeInteger(value)is your warning light
Where the analogy stops: The real Number format is binary floating point, not a decimal calculator display. The display analogy is just a friendly way to remember the precision limit.
The rule of thumb is simple: if a value is a normal UI count, loop counter, screen coordinate, percentage, or decimal measurement, use Number. If it is a whole integer whose exact digits matter and it may cross the safe range, consider BigInt.
The n suffix: writing a BigInt
The easiest way to create a BigInt is to put n at the end of an integer literal. 10 is a Number. 10n is a BigInt. The suffix only works on whole-number literals: there is no 1.5n, because BigInt cannot store a fractional part.
const exact = 10n;console.log(typeof exact);console.log(exact + 5n);console.log(Boolean(0n));Line 2 prints "bigint". Line 3 works because both sides are BigInt. Line 4 prints false, because 0n is falsy, just like 0 is falsy for Number. Any nonzero BigInt, including -1n, is truthy.
Use the suffix when you write the number in code: 123n. Use the function when the digits arrive as text: BigInt("123"). Avoid BigInt(9007199254740993), because the Number may already be rounded before BigInt sees it.
BigInt arithmetic: exact, whole-number math
STEP THROUGHBigInt supports the familiar integer operators: +, -, *, **, /, and %. The important condition is that both operands must be BigInt. The important surprise is division: BigInt has no decimals, so division truncates toward zero.
Step through the replay. The first line computes a huge power exactly: 10n ** 20n. Then change the operands and compare 7n / 2n, -7n / 2n, and a larger pair.
Predict each console line, then step through the exact BigInt operations JavaScript ran.
script
const a = 7n;const b = 2n;console.log(power);console.log(a / b);console.log(a % b);console.log(typeof 10n);7n / 2n is 3n, not 3.5. -7n / 2n is -3n, not -4n. JavaScript drops the fractional part in the direction of zero.
This makes BigInt perfect for exact integer algorithms—factorials, counters, IDs, bit masks, and hash values—but not for decimal arithmetic. If your calculation needs a half, a tenth, or a percentage, stay with Number for now.
Mixing with Number: compare carefully, convert deliberately
STEP THROUGHBigInt and Number are different primitive types. JavaScript allows some comparisons across them, but it refuses arithmetic that mixes them. That refusal is a feature: it prevents JavaScript from guessing whether you wanted exact BigInt behavior or flexible Number behavior.
If someone writes “1 euro plus 1 dollar,” a careful accountant asks for a conversion rate. JavaScript acts like that accountant for BigInt arithmetic: convert first, then add.
- In real life: €1 + $1 is unclear
- In JavaScript:
1n + 1is unclear - In real life: Convert dollars to euros first
- In JavaScript: Convert with
BigInt(1)orNumber(1n)first - In real life: A bad exchange rate loses value
- In JavaScript: Converting a huge BigInt to Number can lose precision
Where the analogy stops: Number and BigInt are not currencies; the point is that JavaScript makes you choose a conversion instead of guessing for you.
Comparisons, explicit conversions, precision loss, and two common errors—one line at a time.
script
console.log(1n === 1);console.log(2n > 1);console.log(BigInt("123"));console.log(Number(9007199254740993n));console.log(BigInt(1.5));console.log(1n + 1);| Expression | Result | Why |
|---|---|---|
1n == 1 | true | Loose equality compares the numeric value across types. |
1n === 1 | false | Strict equality also checks the type. |
2n > 1 | true | Relational comparisons can compare BigInt and Number. |
1n + 1 | TypeError | Arithmetic cannot mix the two numeric types. |
BigInt(1.5) | RangeError | BigInt cannot represent a fraction. |
Number(9007199254740993n) | 9007199254740992 | The huge integer rounds when it becomes Number. |
JSON.stringify({ id: 1n }) throws in JavaScript because JSON has no BigInt value. APIs commonly send IDs that might exceed Number’s safe range as strings: "9007199254740993". Keep them as strings for display and equality, or convert with BigInt(idText) only when you need integer arithmetic.
A few more boundaries are worth remembering: unary +10n throws, Math.max(1n) throws because Math functions expect Numbers, and sorting a mixed array needs an explicit comparator such as (a, b) => a < b ? -1 : a > b ? 1 : 0 instead of subtraction.
BigInt.asIntN and BigInt.asUintN: fixed-width wrapping
INTERACTIVEMost beginner JavaScript values grow or shrink without you choosing a number of bits. But some systems do care: a 64-bit database ID, a hash value, a binary file format, or a low-level API might say “keep exactly 64 bits.” BigInt has two helpers for that: BigInt.asUintN for unsigned interpretation and BigInt.asIntN for signed interpretation.
A car odometer has a fixed number of digit windows. Once every window shows 9, the next mile rolls it back to 0. Fixed-width integers do the same thing with bits.
- In real life: A 3-digit odometer goes 998, 999, 000
- In JavaScript: A fixed-width integer wraps after its largest bit pattern
- In real life: Reading the same digits as mileage
- In JavaScript:
asUintNreads the bits as unsigned - In real life: Reading the same digits as a signed offset
- In JavaScript:
asIntNreads the bits as signed two’s-complement
Where the analogy stops: Real odometers use decimal digits. These helpers wrap binary bit patterns, but the roll-over feeling is the same.
| Call | Result | Meaning |
|---|---|---|
BigInt.asUintN(8, 257n) | 1n | Eight unsigned bits hold 0–255, so 257 wraps to 1. |
BigInt.asIntN(8, 255n) | -1n | The same 8 bits interpreted as signed two’s-complement represent -1. |
BigInt.asUintN(64, -1n) | 18446744073709551615n | Unsigned 64-bit -1 wraps to the largest 64-bit value. |
console.log(BigInt.asUintN(8, 257n));console.log(BigInt.asIntN(8, 255n));console.log(BigInt.asUintN(64, -1n));BigInt.asUintN(8, 257n)
1n
8 unsigned bits hold 0 through 255, so 257 wraps to 1.
BigInt.asUintN(8, 257n) returns 1n. 8 unsigned bits hold 0 through 255, so 257 wraps to 1.
You will not use these helpers for ordinary counting. Reach for them when you cross a boundary to another system that has fixed-width integers: binary protocols, 64-bit hashes, database IDs, or typed array code in a later lesson.
Where you will use BigInt
BigInt is a specialist. Most JavaScript calculations should still use Number. Choose BigInt when the value is a whole number, exactness matters, and the value might leave the safe Number range.
- A shop price with cents, like 19.99
- The number of atoms in a mole, used as a science estimate
- A 64-bit database ID that might be 9007199254740993
- A completion percentage such as 82.5%
- The exact value of 30!
- A normal loop counter from 0 to 100
Sort each scenario by the safest representation. The explanations point out why BigInt is not always the right tool.
Common real-world cases include:
- Large IDs. APIs often send 64-bit IDs as strings so browsers do not round them. Convert only if you need arithmetic.
- Factorials and combinatorics. Values like
30!are whole numbers and grow very quickly. - Whole-unit money at huge scale. If you store cents as whole units and totals may be enormous, BigInt can keep them exact. It still cannot store
19.99directly. - Cryptography, hashes, and binary interop. These often use fixed-width integer rules where
asIntNandasUintNmatter.
Do not use BigInt for decimal measurements, percentages, ordinary animation math, or performance-sensitive number crunching unless you have measured and know exact integers are required. BigInt is exact, not automatically faster.
Common BigInt misconceptions
“BigInt is just a bigger Number.”
It is a different primitive type. That is why typeof 10n is "bigint" and 1n === 1 is false.
“BigInt fixes decimal math.”
BigInt has no fractional part. It cannot represent 0.1, 19.99, or 3.5.
“JavaScript will convert it when needed.”
Not for arithmetic. 1n + 1 throws so you must choose 1n + BigInt(1) or Number(1n) + 1.
“BigInt works everywhere Number works.”
Math.max(1n), unary +10n, and direct JSON.stringify of BigInt all throw.
“If an API sends a huge ID, immediately convert it.”
If you only display, store, or compare the ID, keeping the string is often safest. Convert only for integer arithmetic.
BigInt division and remainder are useful together: the division gives the whole quotient, and % gives what was left over. That pair shows up in algorithms that split a giant integer into chunks.
Practice: exact whole numbers
5 EXERCISESRead the code and type the three console outputs in order.
console.log(7n / 2n);
console.log(typeof 10n);
console.log(1n === 1);7n / 2n prints 3n, typeof 10n prints bigint, and 1n === 1 prints false because the types differ.
The starter code throws. Change the fee so the addition is all BigInt, then predict the output.
const cents = 99n;
const fee = 1;
console.log(cents + fee);const cents = 99n;
const fee = BigInt(1);
console.log(cents + fee);Both operands are BigInt, so + is allowed and the exact result is 100n.
Write a loop that multiplies 1n by every BigInt from 2n through 25n, then logs the exact result.
let total = 1n;
for (let value = 2n; value <= 25n; value += 1n) {
total = total * value;
}
console.log(total);Every value in the loop is BigInt, so there is no mixing error. The exact result is 15511210043330985984000000n.
Many APIs send large IDs as strings. Read this one as BigInt and add one without losing precision.
const idText = "9007199254740993";
const id = BigInt(idText);
console.log(id + 1n);const idText = "9007199254740993";
const id = BigInt(idText);
console.log(id + 1n);Converting from the string keeps the exact ID. Adding 1n prints 9007199254740994n.
Predict the output without running it first.
console.log(BigInt.asUintN(8, 260n));BigInt.asUintN(8, 260n) keeps 8 bits, so it wraps modulo 256 and prints 4n.
Quiz: check your understanding
8 QUESTIONSFor every code question, identify the type of each value before you compute. The explanations matter as much as the score.
Question 1 of 8What is the first unsafe integer above Number.MAX_SAFE_INTEGER?
Choose an answer to see the explanation.
Question 2 of 8What does this comparison print?
Read the code, then predictconsole.log(2 ** 53 + 1 === 2 ** 53);Choose an answer to see the explanation.
Question 3 of 8Which literal creates a BigInt?
Choose an answer to see the explanation.
Question 4 of 8What does this BigInt division print?
Read the code, then predictconsole.log(7n / 2n);Choose an answer to see the explanation.
Question 5 of 8What happens when this mixed addition runs?
Read the code, then predictconsole.log(1n + 1);Choose an answer to see the explanation.
Question 6 of 8What do these equality checks print?
Read the code, then predictconsole.log(1n == 1); console.log(1n === 1);Choose an answer to see the explanation.
Question 7 of 8What does this unsigned wrap print?
Read the code, then predictconsole.log(BigInt.asUintN(8, 257n));Choose an answer to see the explanation.
Question 8 of 8Which value is falsy?
Choose an answer to see the explanation.
Key takeaways
Number.MAX_SAFE_INTEGERis9007199254740991; beyond it, Number may skip integers.- Add
nto an integer literal to create a BigInt, such as10n.typeof 10nis"bigint". - BigInt arithmetic is exact for whole numbers. Division truncates toward zero, and
0nis falsy. - Arithmetic cannot mix BigInt and Number. Convert deliberately, and watch for precision loss when converting huge BigInts to Number.
BigInt.asIntNandBigInt.asUintNwrap values to fixed-width signed or unsigned integer ranges.
BigInt in one line.
A BigInt is an exact whole-number value written like 10n, used when Number’s safe integer range is not enough.
Up next: Type conversion, where you will learn String(), Number(), Boolean(), and why implicit conversion is helpful only when you understand it.