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 numbers that aren't safeUse Number.MAX_SAFE_INTEGER and Number.isSafeInteger to tell when Number starts rounding whole numbers.
- 02Write exact BigIntsWrite BigInts with the n suffix, do math with them, and change types on purpose so you never mix BigInt and Number by accident.
- 03Fit numbers into a fixed sizeExplain how BigInt.asIntN and BigInt.asUintN make a value fit into 8 or 64 bits.
BigInt in one sentence
BigInt is a JavaScript type for whole numbers that stay exact, however big they get. A whole number, also called an integer, has no decimal part, like 7 or -20.
You write a BigInt like a normal number with an n on the end: 10n. The n is called a suffix, because it goes at the end. It tells JavaScript: "keep every digit of this whole number."
Why do you need it? The Data types lesson listed bigint as one of the eight basic value types. The Numbers lesson showed a problem with the normal Number type:
- Number is great for everyday math: prices, percentages, decimals, and the
Mathtools. - Number keeps whole numbers exact only up to
Number.MAX_SAFE_INTEGER, which is9007199254740991. - Past that, Number starts to skip some whole numbers. It rounds them to a number nearby.
BigInt never skips. Every digit stays exact.
A pocket calculator has a screen with room for only so many digits. When a number is too long, the calculator rounds it to fit, and it doesn't warn you. Now picture writing the digits on a strip of paper instead. When you need more room, you add more paper, and every digit stays exact. On this strip you only write whole numbers. There is no decimal point.
- In real life: A calculator screen that fits about 16 digits
- In JavaScript: Number: fast, but only about 16 exact digits
- In real life: A strip of paper you can keep making longer
- In JavaScript: BigInt: every digit stays exact, as long as the computer has memory
- In real life: The calculator has a decimal point
- In JavaScript: Number can hold fractions like
0.5 - In real life: You only write whole numbers on the strip
- In JavaScript: BigInt has no decimal part
In this lesson you will:
- see where Number stops being exact,
- write BigInts with the
nsuffix, - do exact math with BigInts, step by step,
- fix the common error "Cannot mix BigInt and other types",
- use
BigInt.asIntNandBigInt.asUintNto fit a number into a fixed size.
Number.MAX_SAFE_INTEGER: where Number stops being exact
INTERACTIVEA safe integer is a whole number that Number stores exactly. With safe integers, adding 1 always gives the next whole number, and two different numbers never look the same.
The largest safe integer is 9007199254740991. JavaScript keeps it in Number.MAX_SAFE_INTEGER, so you don't have to remember the digits. Above it, Number can't store every whole number. Some are rounded to a number next to them.
Try the explorer below. Line 1 saves the largest safe integer as max. Lines 3 to 5 add 1, 2, and 3 to it. Look closely at max + 1 and max + 2: Number prints the same value for both. Line 8 does the same addition with BigInt, and the answer 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
Line 6 prints true, because both Number sums are rounded to the same value.
Number gives 9007199254740992, 9007199254740992, 9007199254740994 for max + 1, max + 2, and max + 3. The BigInt line for +1 is exact: 9007199254740992n.
The code uses three tools you may not know yet:
2 ** 53means 2 to the power of 53. The**operator raises a number to a power. Line 6 printstrue, because2 ** 53 + 1is rounded to the same value as2 ** 53.Number.isSafeInteger(value)givestrueif the value is a safe integer, andfalseif not. Line 7 uses it.BigInt(max)on line 8 turns the Numbermaxinto a BigInt. That is fine here, becausemaxis still exact.
max + 1 and max + 2 come out as the same value, so one whole number is lost. With BigInt, adding 1n and 2n gives two different answers, and both are exact.A cheap calculator doesn't beep when a number is too long for its screen. It just rounds it. Number does the same above the largest safe integer. It still gives you a value, but some of the whole numbers near it are missing.
- In real life: The screen is full
- In JavaScript: Number has used up its exact digits
- In real life: The calculator rounds without a warning
- In JavaScript:
max + 2can come out the same asmax + 1 - In real life: A warning light would help
- In JavaScript:
Number.isSafeInteger(value)is your warning light
A simple rule:
- Use Number for everyday values: counts on a page, loop counters, positions on the screen, percentages, and decimals.
- Think about BigInt when the value is a whole number, every digit matters, and it might grow past
Number.MAX_SAFE_INTEGER.
The n suffix: how to write a BigInt
The easiest way to make a BigInt is to write a whole number with n at the end. A value written straight into your code is called a literal. So 10 is a Number literal, and 10n is a BigInt literal.
The n only works on whole numbers. You can't write 1.5n, because a BigInt has no decimal part.
const exact = 10n;console.log(typeof exact);console.log(exact + 5n);console.log(Boolean(0n));Line by line:
- Line 1 makes a BigInt,
10n, and saves it asexact. - Line 2 asks for its type with
typeof, which gives a value's type as text. It printsbigint. - Line 3 adds
5n. Both sides are BigInts, so this works. It prints15n. - Line 4 prints
false.Boolean(value)tells you whether a value counts as true or false.0ncounts as false, just like the Number0. A value that counts as false is called falsy.
Every BigInt except 0n counts as true, even -1n.
10 and 10n is the n, but they are different types. The n only works on whole numbers, so 1.5n is an error.Write the n when you type the number into your code: 123n. Use the BigInt() function when the digits come as text: BigInt("123").
Don't write BigInt(9007199254740993). That number is too big for Number, so it is already rounded before BigInt() sees it.
const fromText = BigInt("123");
console.log(fromText);
console.log(fromText + 1n);Line 1 turns the text "123" into the BigInt 123n. The digits never pass through Number, so none of them can be rounded. Line 2 prints 123n. Line 3 adds 1n and prints 124n, which shows the result really is a BigInt.
console.log(BigInt(1.5));This line throws a RangeError. That is the error JavaScript throws when a value is outside what is allowed. A BigInt can't hold the .5.
BigInt math: exact, with whole numbers only
STEP THROUGHBigInt works with the math operators you already know:
+adds,-subtracts, and*multiplies.**raises a number to a power./divides.%gives the remainder: what is left over after dividing.
There is one rule: both values must be BigInts. The values on each side of an operator are called operands. In 7n / 2n, the operands are 7n and 2n.
There is also one surprise: division. A BigInt can't have a decimal part, so division cuts the decimal part off.
Press Step to walk through the replay. Line 1 works out 10n ** 20n, which is 1 followed by 20 zeros, exactly. Then pick other values for lines 2 and 3, and compare 7n / 2n, -7n / 2n, and 25n / 4n.
Guess what each console line prints. Then step through and watch JavaScript do the exact BigInt math.
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 cuts the decimal part off, so the answer always moves toward zero. This is called truncating toward zero.
So BigInt is a good fit for exact whole-number work, such as:
- factorials, like
5!, which means 1 × 2 × 3 × 4 × 5, - counters and IDs that grow very large,
- hash values, which are long numbers worked out from some data.
BigInt is not for decimals. If your math needs a half, a tenth, or a percentage, use Number.
Mixing with Number: compare freely, change the type on purpose
STEP THROUGHBigInt and Number are two different types. JavaScript lets you compare one with the other. But it won't do math that mixes them, like 1n + 1. It throws a TypeError instead. A TypeError is the error JavaScript throws when a value has the wrong type for a job.
This error helps you. Without it, JavaScript would have to guess what you wanted: an exact BigInt answer, or a Number answer that can have decimals. So it asks you to choose.
Someone asks you to add 1 euro and 1 dollar. A careful accountant first asks which currency the answer should be in. Then they change one amount into that currency, and add. JavaScript acts like that accountant: change one side first, then add.
- In real life: €1 + $1 is unclear
- In JavaScript:
1n + 1is unclear - In real life: Change the dollars into euros first
- In JavaScript: Change one side first, with
BigInt(1)orNumber(1n) - In real life: A bad exchange rate loses money
- In JavaScript: Changing a huge BigInt into a Number can lose digits
1n + 1 mixes a BigInt and a Number, so it throws. Change the Number first with BigInt(1), and both sides are BigInts.Step through the replay below. It runs seven lines, one at a time:
- Lines 1 to 3 compare a BigInt with a Number.
- Lines 4 and 5 change a value from one type to the other, on purpose.
Number(value)turns a value into a Number. - Lines 6 and 7 throw errors.
Comparisons, type changes you choose, a rounded value, 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);The table sums up the replay. Read each row as: "when I write this, I get this result, for this reason."
| When you write | What you get | Why |
|---|---|---|
1n == 1 | true | == compares only the amount, and both amounts are 1. |
1n === 1 | false | === also checks the type, and the types are different. |
2n > 1 | true | You can compare a BigInt with a Number using > and <. |
1n + 1 | TypeError | Math can't mix a BigInt and a Number. |
BigInt(1.5) | RangeError | A BigInt can't hold a decimal part. |
Number(9007199254740993n) | 9007199254740992 | The huge number is rounded when it becomes a Number. |
JSON is the text format that websites use to send data. JSON.stringify(value) turns a value into JSON text. JSON has no BigInt type, so JSON.stringify({ id: 1n }) throws an error.
So servers often send very large IDs as text: "9007199254740993". Keep the ID as text to show it or compare it. Turn it into a BigInt with BigInt(idText) only when you need to do math with it.
A few more things don't work with BigInt:
+10nthrows. A+in front of a value turns it into a Number, and BigInt refuses.Math.max(1n)throws, because theMathtools only take Numbers.- Sorting a list that mixes BigInts and Numbers needs care. You'll see how further down this page.
BigInt.asIntN and BigInt.asUintN: fit a number into a fixed size
INTERACTIVEComputers store numbers as bits. A bit is a single 0 or 1. With 8 bits you can make 256 different patterns, so 8 bits can count from 0 to 255.
Most of the time in JavaScript, you never choose how many bits a number uses. But some other systems fix the size. For example, a database ID, a hash value, or a file format may say "this number is exactly 64 bits." BigInt has two tools for this:
BigInt.asUintN(bits, value)keeps only the given number of bits and reads them as unsigned: zero or positive only.BigInt.asIntN(bits, value)keeps the same bits but reads them as signed: the top half of the patterns stand for negative numbers.
A car's mileage counter has a fixed number of digit wheels. When every wheel shows 9, the next mile turns them all back to 0. Fixed-size numbers do the same thing with bits.
- In real life: A 3-digit counter goes 998, 999, 000
- In JavaScript: A fixed-size number starts again at 0 after its largest value
- In real life: Read the digits as miles driven
- In JavaScript:
asUintNreads the bits as zero or positive - In real life: Read the digits as steps forward or back
- In JavaScript:
asIntNreads the bits so that some of them mean negative numbers
The table shows three calls. Read each row as: "this call gives this result, and here is why."
| Call | Result | Why |
|---|---|---|
BigInt.asUintN(8, 257n) | 1n | 8 unsigned bits hold 0 to 255. 257 is 1 more than 256, so the count starts again and lands on 1. |
BigInt.asIntN(8, 255n) | -1n | Read as signed, the 8-bit pattern for 255 means -1. |
BigInt.asUintN(64, -1n) | 18446744073709551615n | Unsigned 64 bits can't hold -1, so it goes around to the largest 64-bit value. |
1n.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 to 255. After 255 the count starts again at 0, so 257 lands on 1.
BigInt.asUintN(8, 257n) returns 1n. 8 unsigned bits hold 0 to 255. After 255 the count starts again at 0, so 257 lands on 1.
You won't need these tools for normal counting. Use them when your code works with another system that uses fixed-size numbers: binary file formats, 64-bit hash values, or database IDs. A later lesson on typed arrays uses them too.
Where you will use BigInt
Most JavaScript math should still use Number. Choose BigInt only when all three of these are true:
- the value is a whole number,
- every digit must be exact,
- the value might grow past
Number.MAX_SAFE_INTEGER.
- A shop price with cents, like 19.99
- A science measurement that is only an estimate, like the number of atoms in a spoon of water
- A 64-bit database ID that might be 9007199254740993
- A completion percentage such as 82.5%
- The exact value of 30! (1 × 2 × 3 × … × 30)
- A normal loop counter from 0 to 100
Put each value in the best group. Each answer explains why BigInt is not always the right choice.
Here is where BigInt shows up in real code:
- Large IDs. Servers often send 64-bit IDs as text, so the browser doesn't round them. Turn one into a BigInt only if you need to do math with it.
- Factorials and counting combinations. Values like
30!are whole numbers that grow very fast. - Money counted in cents, at huge sizes. If you store money as whole cents and totals can get enormous, BigInt keeps them exact. It still can't store
19.99directly. - Security code, hash values, and binary data. These often use fixed-size numbers, where
asIntNandasUintNmatter.
const idText = "9007199254740993";
const id = BigInt(idText);
console.log(id + 1n);Line 1 holds the ID as text. Line 2 turns the text straight into a BigInt, so every digit is kept. Line 3 adds 1n and prints 9007199254740994n.
Don't use BigInt for decimal measurements, percentages, or animation math. Don't use it to make code faster, either. BigInt is exact, but it is often slower than Number.
Common BigInt misconceptions
“BigInt is just a bigger Number.”
It is a different type. That is why typeof 10n is "bigint", and 1n === 1 is false.
“BigInt fixes decimal math.”
A BigInt has no decimal part. It can't hold 0.1, 19.99, or 3.5.
“JavaScript will change the type for me.”
Not for math. 1n + 1 throws. You choose: 1n + BigInt(1) gives 2n, and Number(1n) + 1 gives 2.
“BigInt works everywhere Number works.”
Math.max(1n), +10n, and JSON.stringify on a BigInt all throw.
“If a server sends a huge ID, turn it into a BigInt right away.”
If you only show, store, or compare the ID, keeping it as text is often safest. Turn it into a BigInt only when you need to do math with it.
const record = { id: 1n };
console.log(JSON.stringify(record));console.log(Math.max(1n));Both blocks above throw a TypeError when you run them.
const values = [2n, 10, 1n];
values.sort((left, right) => left < right ? -1 : left > right ? 1 : 0);
console.log(values);Line by line:
- Line 1 makes a list with two BigInts and one Number.
- Line 2 sorts the list.
.sort()calls your function with two items at a time,leftandright. The function gives-1ifleftshould come first,1ifrightshould come first, and0if they are equal. The? :is a short if/else:a ? b : cmeans "if a, then b, else c". - Line 3 prints
[ 1n, 2n, 10 ].
The function uses only < and >, which can compare a BigInt with a Number. The common shortcut left - right would mix the types and throw.
Division and remainder work well together. / tells you how many whole times one number fits into another, and % tells you what is left over. For example, 17n / 5n is 3n, and 17n % 5n is 2n. Programs use this pair to cut a huge number into smaller pieces.
Practice: exact whole numbers
5 EXERCISESRead the code. Type the three lines it prints, in order.
console.log(7n / 2n);
console.log(typeof 10n);
console.log(1n === 1);7n / 2n prints 3n. typeof 10n prints bigint. 1n === 1 prints false, because the types are different.
The starter code throws an error. Change the fee so both values are BigInts. Then type what the program prints.
const cents = 99n;
const fee = 1;
console.log(cents + fee);const cents = 99n;
const fee = BigInt(1);
console.log(cents + fee);Now both values are BigInts, so + works. The exact result is 100n.
25! means 1 × 2 × 3 × … × 25. Write a loop that starts with 1n and multiplies by every BigInt from 2n to 25n. Then print the result.
let total = 1n;
for (let value = 2n; value <= 25n; value += 1n) {
total = total * value;
}
console.log(total);Every value in the loop is a BigInt, so nothing is mixed. The exact result is 15511210043330985984000000n.
Servers often send large IDs as text. Turn this one into a BigInt and add one, without losing any digits.
const idText = "9007199254740993";
const id = BigInt(idText);
console.log(id + 1n);const idText = "9007199254740993";
const id = BigInt(idText);
console.log(id + 1n);Turning the text straight into a BigInt keeps every digit. Adding 1n prints 9007199254740994n.
Predict what it prints before you run it.
console.log(BigInt.asUintN(8, 260n));BigInt.asUintN(8, 260n) keeps only 8 bits. After 255 the count starts again at 0, so 256 becomes 0 and 260 becomes 4n.
Quiz: check your understanding
8 QUESTIONSFor each code question, first find the type of each value: BigInt or Number. Then work out the answer. Read the explanation for each choice, too.
Question 1 of 8Which is the first whole number past 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 of these is a BigInt literal?
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 line runs?
Read the code, then predictconsole.log(1n + 1);Choose an answer to see the explanation.
Question 6 of 8What do these two comparisons 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 8-bit call 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, which means it counts as false?
Choose an answer to see the explanation.
Key takeaways
Number.MAX_SAFE_INTEGERis9007199254740991. Above it, Number may skip whole numbers.- Put
nafter a whole number to make a BigInt, like10n.typeof 10nis"bigint". - BigInt math is exact for whole numbers. Division cuts off the decimal part, toward zero.
0nis falsy. - Math can't mix BigInt and Number. Change one side on purpose. Be careful: a huge BigInt can lose digits when it becomes a Number.
BigInt.asIntNandBigInt.asUintNfit a value into a fixed number of bits, signed or unsigned.
BigInt in one line.
A BigInt is an exact whole number, written like 10n. Use it when Number's safe range is not big enough.
Up next: Type conversion. You will learn String(), Number(), and Boolean(), and when JavaScript changes a value's type on its own.