Random number generator JavaScript: Math.random() explained with examples

A random number generator in JavaScript almost always starts with one method: Math.random(). It returns a decimal between 0 and 1, and everything else, dice rolls, OTPs, shuffled arrays, secure tokens, gets built on top of that single line. I have used random numbers in games, verification flows and test data scripts, and the same handful of formulas cover nearly every case. This guide walks through Math.random(), the integer formulas you will reuse constantly and where Math.random() falls short.

What is Math.random() in JavaScript

Math.random() is a built-in method on the JavaScript Math object. It takes no parameters and returns a floating-point number that is greater than or equal to 0 and less than 1. So 0 is a possible output, but 1 never is.

const value = Math.random();
console.log(value);
// 0.7283918234219845

Every call produces a new value, and the numbers spread evenly across that 0 to 1 range, so no small band of decimals shows up more often than another. Under the hood, Math.random() is a pseudo-random number generator (PRNG), a formula that produces numbers that look random but come from a fixed algorithm rather than true physical randomness. That distinction matters more than it seems, and I will come back to it later in this guide.

How to generate a random number in a range in JavaScript

Most real use cases need a number between two chosen values, not a raw decimal between 0 and 1. You get there with a small formula that scales the output:

Math.random() * (max - min) + min;

This multiplies the 0 to 1 range by the width of your target range, then shifts it up by the minimum. Here is the pattern as a reusable function:

function getRandomDecimal(min, max) {
  return Math.random() * (max - min) + min;
}

console.log(getRandomDecimal(5, 10));
// 7.392579122270686

The result stays inclusive of min and exclusive of max, since Math.random() itself never reaches 1. This version returns decimals, which is fine for things like random opacity values or physics simulations, but most day to day use cases want whole numbers instead.

How to build a random number generator for integers in JavaScript

Whole numbers are what you need for dice rolls, array indexes and IDs, and getting them takes one more step: rounding the decimal down with Math.floor(). Math.floor() rounds any number down to the nearest integer, so 3.9 becomes 3 and 0.1 becomes 0.

Random integer with an exclusive maximum

function getRandomInt(max) {
  return Math.floor(Math.random() * max);
}

console.log(getRandomInt(10));
// returns 0 through 9

Multiplying by max gives a decimal from 0 up to (but not including) max, and Math.floor() rounds it down. The output range is 0 to max minus 1.

Random integer with an inclusive maximum

If you want max itself to be a possible result, add 1 before flooring:

function getRandomIntInclusive(max) {
  return Math.floor(Math.random() * (max + 1));
}

console.log(getRandomIntInclusive(10));
// returns 0 through 10

This small change matters more than it looks. Forgetting the + 1 is the most common reason a “1 to 10” random number generator quietly stops short and only ever produces up to 9.

Random integer between a min and max, inclusive

This is the version you will reach for the most, since it lets you set both boundaries:

function getRandomBetween(min, max) {
  min = Math.ceil(min);
  max = Math.floor(max);
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

console.log(getRandomBetween(1, 100));
// returns any integer from 1 to 100

Math.ceil() and Math.floor() on min and max guard against passing in decimals by accident, so the function always works with clean integers before the random calculation runs.

Common mistakes when generating random integers in JavaScript

The formulas above look simple, but a few small errors show up often enough to be worth naming directly.

The most common one is skipping Math.floor() entirely and multiplying Math.random() by a whole number, then feeding that straight into code that expects an integer, like an array index. The result is a decimal, and most code that indexes into an array with a decimal silently returns undefined instead of throwing an error.

A second one is using Math.round() instead of Math.floor() to convert to an integer. It looks like it should work, but Math.round() gives the first and last values in a range about half the probability of the values in the middle, since only 0.5 rounds up to 1 while a full unit width rounds down to it.

A third is multiplying by the wrong number when you want an inclusive range. Multiplying by max instead of (max – min + 1) is the single most common off-by-one error in random integer code, and it either excludes your intended maximum or produces a number just outside the range you meant to allow.

Practical uses for a random number generator in JavaScript

The formulas above cover the math. Here is how they show up in code you would actually ship, from small UI touches like a coin flip to backend tasks like generating a verification code.

Roll a dice

const roll = Math.floor(Math.random() * 6) + 1;
console.log(`You rolled a ${roll}`);

This uses template literals to drop the roll straight into a message string instead of concatenating pieces with plus signs.

Flip a coin

const result = Math.random() < 0.5 ? "Heads" : "Tails";
console.log(result);

Since Math.random() spreads evenly across 0 to 1, checking whether it lands below 0.5 gives you a fair coin flip in one line. The ternary is one of the more common JavaScript operators for exactly this kind of two-way branch.

Pick a random item from an array

const fruits = ["apple", "banana", "cherry", "date"];
const randomIndex = Math.floor(Math.random() * fruits.length);
console.log(fruits[randomIndex]);

Multiplying by the array’s length guarantees the index always lands inside the array’s bounds, since Math.random() never actually reaches 1.

Shuffle an array with the Fisher-Yates algorithm

A common shortcut is array.sort(() => Math.random() - 0.5), but that trick produces a biased shuffle because sort comparators were never built for randomness. The Fisher-Yates algorithm gives every possible ordering an equal chance:

function shuffle(array) {
  for (let i = array.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [array[i], array[j]] = [array[j], array[i]];
  }
  return array;
}

console.log(shuffle([1, 2, 3, 4, 5]));

The loop walks backward through the array, swapping each element with a random one that has not been placed yet, which is why the result is genuinely unbiased.

Generate a random boolean

const isTrue = Math.random() < 0.5;
console.log(isTrue);

This is the same idea as the coin flip, just returned as true or false instead of a string. It comes up in feature flags, A/B test splits and anywhere you need a coin-flip decision baked straight into a condition.

Generate a random color

function getRandomColor() {
  const r = Math.floor(Math.random() * 256);
  const g = Math.floor(Math.random() * 256);
  const b = Math.floor(Math.random() * 256);
  return `rgb(${r}, ${g}, ${b})`;
}

console.log(getRandomColor());
// "rgb(128, 45, 210)"

RGB channels run from 0 to 255, so multiplying by 256 and flooring the result covers the full range for each channel.

Build a verification code or OTP

Sites send a short numeric code to confirm an email address or phone number, and that code is a random integer padded to a fixed length:

function generateOTP(length = 6) {
  let otp = "";
  for (let i = 0; i < length; i++) {
    otp += Math.floor(Math.random() * 10);
  }
  return otp;
}

console.log(generateOTP());
// "483920"

This same building block generates alphanumeric strings for random passwords by swapping the digit pool for a wider character set.

Assign random object IDs

When you need a quick identifier for an object without pulling in a UUID library, a random integer in a large range works for low-stakes cases like demo data or client-side keys:

function generateId() {
  return Math.floor(Math.random() * 1000000);
}

const user = { id: generateId(), name: "Aditya" };
console.log(user);

CAPTCHA challenges used to lean on random strings the same way, though most sites have since moved to services like Google reCAPTCHA instead of rolling their own.

How to generate cryptographically secure random numbers in JavaScript

Math.random() is not safe for anything security related. Since it is a PRNG, its output is technically predictable if someone can work out the internal state, which makes it a poor choice for session tokens, password reset codes or encryption keys.

For those cases, use the Web Crypto API instead:

const array = new Uint32Array(1);
crypto.getRandomValues(array);
console.log(array[0]);

crypto.getRandomValues() pulls from the operating system’s secure random source rather than a predictable formula, and it is available in every modern browser and in Node.js through the crypto module. Reach for it any time the random value protects something, and stick with Math.random() for everything else, since crypto.getRandomValues() is slower and gives you raw integers rather than a convenient 0 to 1 float.

Is Math.random() truly random in JavaScript

No, and that is by design rather than a flaw. Math.random() is a pseudo-random number generator, so it produces its sequence from a deterministic algorithm and an internal seed value that JavaScript picks for you and never exposes. The output passes statistical randomness tests well enough for games, simulations and UI variation, but it is not derived from genuine physical entropy the way crypto.getRandomValues() is.

One side effect of this design is that you cannot set your own seed natively in JavaScript, so you cannot reproduce the exact same “random” sequence across two runs without a third-party library such as seedrandom. That matters for testing, where a repeatable sequence makes a flaky test deterministic again, but it rarely matters for the dice rolls and shuffles most projects use Math.random() for.

Key takeaways

  • Math.random() returns a float from 0 inclusive to 1 exclusive, never parameters.
  • Scale to a range with Math.random() * (max – min) + min.
  • Add Math.floor() to convert any range formula into whole numbers.
  • Multiply by (max – min + 1) for an inclusive integer range, not just max.
  • Use Math.floor() over Math.round() to keep the distribution even.
  • Fisher-Yates gives an unbiased shuffle, the sort-based trick does not.
  • Math.random() is not secure. Use crypto.getRandomValues() for tokens and keys.
  • JavaScript offers no native way to seed Math.random().

Frequently asked questions (FAQs)

How do I generate a random number between two numbers in JavaScript?

Use Math.random() * (max – min) + min for a decimal. Wrap it in Math.floor(Math.random() * (max – min + 1)) + min for a whole number instead.

Why does Math.random() never return exactly 1?

Math.random() returns a value in the half-open range 0 to 1, where 0 is possible but 1 is not. Any scaled range keeps that same exclusive upper bound.

Can Math.random() generate negative numbers in JavaScript?

Not directly, since it only outputs values from 0 to 1. Multiply the result by -1, or use a negative min and max, to push the output below zero.

Is Math.random() safe for generating passwords or tokens?

No. Math.random() is a predictable PRNG and unsuitable for anything security sensitive. Use crypto.getRandomValues() from the Web Crypto API for passwords, tokens and session IDs instead.

How do I pick a random element from an array in JavaScript?

Multiply Math.random() by the array’s length, then pass the floored result as the index: array[Math.floor(Math.random() * array.length)] always lands inside the array’s bounds.

Why does my random number generator sometimes skip the maximum value?

You are likely multiplying by max instead of (max – min + 1). Since Math.random() never reaches 1, plain multiplication excludes the top value unless you widen the range.

Can I set a seed for Math.random() to get repeatable results?

Not natively. JavaScript gives Math.random() an internal seed you cannot access or set, so repeatable sequences require a third-party library like seedrandom instead of the built-in method.

Conclusion

Random numbers in JavaScript come down to one method and a couple of formulas layered on top of it. Start with Math.random(), reach for Math.floor() when you need whole numbers and switch to crypto.getRandomValues() the moment security enters the picture.

Aditya Gupta
Aditya Gupta
Articles: 518