The Devs Tools

Developer's Guide to Random Number Generator: Best Practices and Examples

August 18, 2026 · The Devs Tools Team

Generating a random integer within a range shows up constantly in non-security contexts: seeding test fixtures with varied sample data, shuffling a quiz question order, sampling rows from a dataset, running a Monte Carlo simulation, or picking a random winner from a list of entries. The building block is almost always Math.random(), which returns a uniformly distributed float in [0, 1). The naive way to map that into an integer range is Math.floor(Math.random() * (max - min + 1)) + min, and for most non-cryptographic purposes this is perfectly adequate — Math.random()'s underlying PRNG (typically xorshift128+ in modern JS engines) has good statistical distribution properties and is fast, even though it is explicitly not suitable for anything security-sensitive since its internal state is neither secret nor unpredictable in the cryptographic sense. The distinction matters: if you're deciding which of three A/B test variants a user sees, or generating placeholder data for a demo, statistical randomness is exactly what you want. If you're generating a password reset token, that's a completely different problem requiring a cryptographically secure generator instead.

[!TIP] Need a batch of random numbers right now? Try our free, local Random Number Generator to generate numbers within a custom range completely offline.


The Modulo Bias Trap

A very common but subtly wrong pattern for generating a random integer in [0, n) uses the modulo operator directly on a raw random value:

// Biased when range doesn't evenly divide the source's range
const biased = Math.floor(rawRandom * 1000000) % n;

This introduces modulo bias: if the source range isn't an exact multiple of n, values in the lower part of the range become slightly more likely than values near the top. The bias is small for a random source with a huge range relative to n, but it compounds noticeably in simulations run millions of times, or when n is large relative to the source's precision. The safer pattern scales directly into the target range without a modulo step:

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

Practical Use Cases

  • Test data generation: seeding a fake dataset with random ages, prices, or IDs for UI testing without hand-writing every value.
  • Sampling: pulling a random subset of rows from a larger dataset for a quick statistical spot-check.
  • Simulation: Monte Carlo-style methods that run a random process thousands of times to approximate a probability distribution.
  • Load/fuzz testing: generating randomized but bounded inputs to exercise edge cases in a function under test.

A Worked Example

Generating 5 random integers between 1 and 100 for a dice-roll simulation:

Range: 1-100, Count: 5
Output: 42, 7, 88, 15, 63

Running this thousands of times and checking the output distribution (e.g., bucketing into deciles) is a quick way to sanity-check that a "random" feature in your app isn't accidentally clustering around certain values due to a range or rounding bug.


Conclusion

Most random-number needs in application code are statistical, not cryptographic, and Math.random() handles them well as long as you avoid the modulo bias trap when mapping into a custom range. Reaching for a proper CSPRNG is only necessary once the randomness needs to be unpredictable to an adversary, not just well-distributed.