skip to content

How do you make random number generation reproducible in Kotlin, and why would you want a seeded generator instead of the default one?

level: middleimportance: should knowfreq 55%

answer

  1. Random(seed) -> reproducible sequence
  2. same seed = same numbers, every platform
  3. Default object is unseeded, not reproducible
  4. stdlib has its own portable PRNG
  5. not secure — use SecureRandom for tokens

basics

~10 s

Create a generator with a fixed seed using Random(seed). Two generators built with the same seed produce the same sequence of numbers, which is great for repeatable tests and debugging.

solid answer

~40 s

Call the `Random(seed: Int)` or `Random(seed: Long)` factory function to get a `Random` instance whose output is fully determined by the seed. Same seed in -> same sequence out, on every platform and every run. This is essential for deterministic tests, reproducible simulations, and debugging — you can replay an exact 'random' scenario. The default `Random` object (the `Default` instance) is unseeded and platform-backed; its sequence is not reproducible across runs. You hold the seeded instance and call methods on it: `val rng = Random(42); rng.nextInt(100)`. Because the algorithm is part of kotlin-stdlib (a portable xorshift-based generator), the sequence is identical across JVM/JS/Native for a given seed — unlike java.util.Random whose sequence is only stable on the JVM. Never use a seeded or any PRNG for security tokens.

code

kotlin · 6 lines
kotlin
import kotlin.random.Random

fun deterministicShuffle(items: List<Int>, seed: Long): List<Int> {
    val rng = Random(seed)
    return items.shuffled(rng) // same seed -> same order every run
}

go deeper

for a junior

Knows Random(seed) exists and gives repeatable numbers for tests.

for a middle

Explains same-seed-same-sequence, distinguishes the seeded instance from the Default object, and uses it for deterministic tests.

for a senior

Knows the stdlib ships its own portable PRNG (cross-platform stable) and that it is not secure; mentions thread-safety caveats.

for a principal

Designs test/sim infrastructure around injectable seeded generators and codifies the security boundary (PRNG vs CSPRNG) in conventions.

## Seeded vs default generators A pseudo-random generator (PRNG) produces a deterministic stream of numbers from an internal **state**. The **seed** is the initial state. Two PRNGs that share the same algorithm and seed produce **byte-for-byte identical sequences**. ### Creating a seeded generator ```kotlin import kotlin.random.Random val rng = Random(42) // Int or Long seed val a = rng.nextInt(100) val b = rng.nextInt(100) // A second Random(42) replays exactly a, then b... ``` `Random(seed)` is a top-level factory function returning a `Random` instance. You then call `nextInt`, `nextDouble`, `nextLong`, `nextBoolean`, etc. on **that instance** (not on the `Random` object). ### The default generator Writing `Random.nextInt(...)` uses `Random.Default`, an **unseeded**, platform-backed, thread-safe generator. Its sequence differs every run — you cannot reproduce it. Good for production randomness, bad for repeatable tests. ### Why seeding matters - **Deterministic tests**: feed a seeded `Random` into the code under test so assertions are stable. - **Reproducible simulations / procedural generation**: a game level or Monte-Carlo run can be regenerated from one seed. - **Debugging**: capture the failing seed, replay it. ### Multiplatform stability Kotlin's stdlib ships its **own** PRNG implementation, so `Random(42)` yields the *same* sequence on JVM, JS, and Native. `java.util.Random(42)` only guarantees stability within the JVM. This portability is a core reason to prefer `kotlin.random.Random`. ### Important warnings - This is **not** cryptographically secure. For tokens/keys use `java.security.SecureRandom` (JVM) or a platform CSPRNG — never `kotlin.random.Random`. - Sharing a single seeded instance across threads without synchronization corrupts the state; the `Default` instance is thread-safe, a custom `Random(seed)` is **not** guaranteed to be. - You can promote a `java.util.Random` to the Kotlin API with `.asKotlinRandom()` and convert back with `.asJavaRandom()` on the JVM.

  • Will Random(42) give the same sequence on JVM and Kotlin/JS?
    Yes — kotlin.random.Random ships its own algorithm in stdlib, so the sequence is identical across all Kotlin platforms for a given seed.
  • Is a seeded kotlin.random.Random safe to use for generating an auth token?
    No. It is a predictable PRNG. Use a cryptographically secure source like java.security.SecureRandom on the JVM.

A seed is like a recipe's exact starting ingredients: follow it identically and you get the same cake every time.

saying these in an interview costs you the question

  • Saying the default Random object can be made reproducible by reusing it
  • Claiming kotlin.random.Random is cryptographically secure
  • Believing java.util.Random(seed) is stable across platforms
  • Confusing per-call seeding with one seeded instance reused across calls

context