fastrand: a small Rust RNG that skips the crypto and the heaviness
A simple and fast random number generator
At a glance
- What is it?
- fastrand is a Rust random number generator built on the Wyrand algorithm, giving you a thread-local generator, a per-instance Rng, sampling and shuffling helpers, and reproducible seeding, all in a crate with no required dependencies. It is explicitly not cryptographically secure, and the manifest keeps the Rust floor at 1.63.
- Who is it for?
- Adopt fastrand if you need random values in a Rust program for simulation, sampling, shuffling or jitter, and you want an API that does not pull in the dependency weight of the rand ecosystem. Do not adopt it for anything security related, because the readme says plainly that Wyrand is not cryptographically secure, and a non-cryptographic generator in a token, key or nonce path is a real vulnerability rather than a style preference.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 96 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A deliberate choice not to be secure
fastrand is a simple and fast random number generator, and the second sentence of the description is the one that governs every decision in it. The implementation uses Wyrand, a simple and fast generator, but not cryptographically secure.
That is stated in the readme rather than buried, and it is the correct framing for a crate like this. Most random number use in a program is not adversarial: shuffling a list, picking a test case, sampling a distribution, jittering a value, generating an identifier for a log line. A cryptographically secure generator is slower, and in the general case a well seeded statistical generator is indistinguishable for those uses.
The one place the distinction matters is anywhere an adversary can observe the output and influence later values. A session token, a password reset link, a nonce, a key derived from randomness, a captcha. For those, a fast non-cryptographic generator is not a performance trade, it is a broken primitive, and the crate is candid enough that you can see exactly where the line is.
The crate comes from smol-rs, the same organisation behind smol-tokio and the other small async building blocks, and the whole design philosophy is visible in the size of the thing. The Cargo.toml lists a single required dependency and it is not required for the normal case: the manifest has three features, default with std, alloc, and js, and the only optional dependency is getrandom, and it is scoped to a specific target section, wasm32 and wasm64 on an unknown operating system, with the wasm_js feature enabled.
So on a normal target, fastrand pulls in nothing at all. The version is 2.5.0, published as v2.5.0 on 2026-07-19, with the last push on the same day, and the author is Stjepan Glavina. The Rust edition is 2018 with a rust-version floor of 1.63, which is a deliberate signal that the crate stays usable on older toolchains.
The API is small, and the global generator does most of the work
The free functions cover the common cases in one line each.
A coin flip is fastrand::bool(). A random i32 is fastrand::i32(..), where the range syntax means the full range of the type. Choosing an element of an array is a two step operation, getting an index with fastrand::usize(..v.len()) and then indexing into the vector, because there is no direct pick-from-slice function in the basic API.
Sampling several values at once is where the library adds something. choose_multiple takes an iterator and a count, and the readme calls out that it runs in O(n) complexity where n is the length of the array, so fastrand::choose_multiple([1, 4, 5], 2) and fastrand::choose_multiple(0..20, 12) both work and both are linear rather than quadratic.
Shuffling is a single call, fastrand::shuffle(&mut v), which takes the slice by mutable reference.
Generating a vector or a string is done with the standard library's repeat_with, which reads naturally:
use std::iter::repeat_with;
let v: Vec<i32> = repeat_with(|| fastrand::i32(..)).take(10).collect();
let s: String = repeat_with(fastrand::alphanumeric).take(10).collect();And the coin flip example is the one the readme leads with, because it is the smallest complete program:
if fastrand::bool() {
println!("heads");
} else {
println!("tails");
}The design decision to use the standard library's repeat_with rather than a bespoke fill function is worth noticing. It means the library exposes a generator rather than a battery of container-specific helpers, and that the composition works with the iterator ecosystem you already use.
Seeding for reproducibility, and the Rng instance for speed
Two mechanisms handle determinism and performance, and they are the two features worth understanding before you use the crate in anger.
The first is seeding. To get reproducible results on every run, you initialise the generator with a seed:
// Pick an arbitrary number as seed.
fastrand::seed(7);
// Now this prints the same number on every run:
println!("{}", fastrand::u32(..));The second is the Rng instance. To be more efficient, you create a new Rng instance instead of using the thread-local generator:
use std::iter::repeat_with;
let mut rng = fastrand::Rng::new();
let mut bytes: Vec<u8> = repeat_with(|| rng.u8(..)).take(10_000).collect();The reason the instance is faster is the thread-local. The global functions go through a thread-local generator, so every call has to reach the current thread's state, and in a tight loop that access is measurable. Owning an Rng gives you a value with the state inline, so the same work has no indirection.
The trade is that an Rng instance is not the global generator, so seeding the global one does not affect it, and the two produce different sequences. A program that mixes the two will not be reproducible, and that is the kind of bug that shows up in a test that passes locally and fails in CI.
The features list also has a consequence worth knowing. The std feature is enabled by default and is required for the global generator and global entropy. Without it, Rng can only be instantiated using the with_seed method, which means a no_std build has to thread a seed through explicitly. The js feature assumes that WebAssembly targets are running in a JavaScript environment, which is how the crate knows to pull in getrandom for entropy on wasm targets.
Where the crate fits in a wider dependency graph
The context that matters is what a Rust program already has in its tree, because choosing a random number source is rarely done in isolation.
The Rust standard library ships no random number generator at all. The `std` feature of fastrand therefore names what the crate adds: it enables the standard library, and it is required for the global generator and global entropy. Without that feature the crate is usable in a no_std setting, but only through the with_seed method on Rng, which means the seed has to be threaded through your own code rather than coming from the platform.
That is why the crate has no required dependencies on a normal target, and it is the strongest argument for it in a large dependency tree. A crate that pulls in the rand ecosystem brings a dependency graph with it, and while that is often fine, it is a graph you have to audit, update and keep compatible with your Rust version. fastrand adds nothing to that graph.
The WebAssembly case is handled separately and is worth a sentence, because it is the one place a dependency appears. For wasm32 and wasm64 targets on an unknown operating system, the manifest pulls in getrandom with the wasm_js feature, and the js feature assumes the target is running in a JavaScript environment. That is the modern way to obtain entropy in a browser, since the Web Crypto API is the only source available there, and it is a single optional dependency scoped to a specific target rather than a blanket one.
The dev-dependency list, rand, wyhash and getrandom, tells you what the project considers worth testing. Comparing fastrand's output against a reference implementation, both for the generator and for the underlying mixing function, is how a fast algorithm is shown to be statistically sound rather than merely fast. The benches directory is there for the same reason.
So the practical pitch is narrow and clean. If you need a secure random number, use a secure generator and accept the cost. If you need a fast, dependency-free, reproducible one for everything else, this crate does that job in a few hundred lines, with a Rust version floor of 1.63 and a dual Apache or MIT licence.
What is deliberately left out
The scope statement in the readme is short and it explains the shape of the crate. This crate aims to expose a core set of useful randomness primitives. For more niche algorithms, consider using the fastrand-contrib crate alongside this one.
So the division is clear. fastrand is the small set of primitives that almost every program needs, and fastrand-contrib is where the unusual generators live. That is a design choice with an obvious benefit, the dependency stays small and the API stays learnable, and an obvious cost, if you need a specific distribution or a specific algorithm you now take a second crate.
The Cargo.toml reinforces the minimalism. The dev-dependencies are rand at 0.10, wyhash at 0.6 and getrandom at 0.4, and those are for the test suite rather than for the crate itself. Having rand as a dev-dependency is a common pattern in the Rust ecosystem for a specific purpose: it lets the test suite compare the fastrand output against a reference implementation, which is how you check that a fast generator is at least statistically correct. The wyhash dependency is the same story, the Wyrand algorithm is built on wyhash, so the tests can compare against the reference implementation of the underlying mixing function.
The repository layout is the standard Cargo one, with src, tests, a benches directory for the benchmarks, a CHANGELOG, and the two licence files. The publish configuration in the manifest lists the release process: update CHANGELOG.md, then create a v2.x.y git tag, which is the version string you see on crates.io.
The licence arrangement is the other thing to check before you depend on it. fastrand is licensed under either the Apache License, Version 2.0 or the MIT license, at your option, and the contribution terms say that unless you explicitly state otherwise, any contribution shall be dual licensed as above without any additional terms. Two permissive licences and a dual licence contribution clause is a friendly setup for a crate that many projects will vendor into their dependency tree.
Editorial conclusion
Adopt fastrand if you need random values in a Rust program for simulation, sampling, shuffling or jitter, and you want an API that does not pull in the dependency weight of the rand ecosystem. Do not adopt it for anything security related, because the readme says plainly that Wyrand is not cryptographically secure, and a non-cryptographic generator in a token, key or nonce path is a real vulnerability rather than a style preference. Before you commit, check the one place in your code where the randomness must be unpredictable, and confirm you are using the Rng instance rather than the global generator in hot paths, since the global one carries a thread-local cost.
Frequently asked questions
Is fastrand cryptographically secure?
No. The readme states that the implementation uses Wyrand, a simple and fast generator, but not cryptographically secure. It is meant for simulation, sampling, shuffling and similar uses rather than for tokens, keys or nonces.
How do I get reproducible random numbers in fastrand?
Seed the global generator with fastrand::seed(7), and the same sequence is produced on every run. Note that seeding the global generator does not affect a separate Rng instance, so a program that mixes the two will not be reproducible.
When should I use an Rng instance instead of the free functions?
When you are in a hot path. The free functions go through a thread-local generator, so each call pays for the thread-local access, while an Rng instance holds its state inline. The readme describes creating an Rng instance as the more efficient option.
What are the feature flags in fastrand?
There are three. std is enabled by default and is required for the global generator and global entropy, and without it Rng can only be instantiated with the with_seed method. alloc is a smaller feature that std depends on. js assumes WebAssembly targets are running in a JavaScript environment and pulls in getrandom for entropy there.
What licence is fastrand under?
Either the Apache License, Version 2.0 or the MIT license, at your option, and contributions are dual licensed the same way unless the contributor says otherwise. The manifest records the licence expression as Apache-2.0 OR MIT.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/smol-rs-fastrand)Was this useful?