crypto-random-string, nanoid, and randomstring are npm packages for generating random strings in JavaScript applications. They all provide utilities to create unpredictable sequences of characters, but differ significantly in design philosophy, security guarantees, configurability, and intended use cases. crypto-random-string focuses exclusively on cryptographically secure randomness for sensitive operations. nanoid is optimized for generating compact, URL-safe unique identifiers with minimal overhead. randomstring offers extensive configuration options including human-readable formats and custom character sets, targeting broader utility beyond just security contexts.
When you need to generate unpredictable, unique identifiers or tokens in JavaScript applications — whether for session IDs, password reset tokens, or temporary file names — not all random string generators are created equal. The three packages crypto-random-string, nanoid, and randomstring each offer distinct approaches to randomness, security, and usability. Let’s examine how they differ in practice.
All three packages rely on cryptographically secure sources when available, but their fallback behavior and guarantees vary.
crypto-random-string uses Node.js’s built-in crypto.randomBytes() (or the Web Crypto API in browsers via bundlers like Webpack). It only generates strings from cryptographically secure entropy and throws an error if such a source isn’t available.
// crypto-random-string: always cryptographically secure
import cryptoRandomString from 'crypto-random-string';
const token = cryptoRandomString({ length: 32 });
// Always safe for secrets, sessions, etc.
nanoid also uses secure randomness by default (crypto.getRandomValues() in browsers, crypto.randomBytes() in Node.js). It’s designed specifically for generating short, URL-safe IDs and never falls back to insecure Math.random().
// nanoid: secure by default, optimized for IDs
import { nanoid } from 'nanoid';
const id = nanoid(); // Default length: 21
// Safe for public identifiers like database keys
randomstring supports multiple entropy sources. By default, it uses crypto.randomBytes() in Node.js, making it secure. However, it also allows explicit use of Math.random() via the charset: 'numeric' or other non-crypto modes if misconfigured — though this is discouraged.
// randomstring: secure by default, but configurable
import randomstring from 'randomstring';
// Secure (uses crypto)
const secureToken = randomstring.generate(32);
// Potentially insecure if you override prng (not shown here — avoid in practice)
⚠️ Important: None of these packages use
Math.random()by default in modern versions, butrandomstring’s API permits insecure configurations if you manually specify a PRNG. Always stick to defaults unless you have a specific reason.
Each package takes a different stance on configurability.
crypto-random-string has a minimal, focused API. You specify only length and optionally a type (like 'hex', 'base64', or custom character set).
// Only length and type
const hex = cryptoRandomString({ length: 16, type: 'hex' });
const custom = cryptoRandomString({ length: 10, characters: 'ABC123' });
nanoid prioritizes brevity and performance for ID generation. Its default export gives you a 21-character URL-safe string with no options. For customization, you import customAlphabet.
// Simple default
const id = nanoid();
// Custom alphabet
import { customAlphabet } from 'nanoid';
const numericId = customAlphabet('0123456789', 10)();
randomstring offers the most configuration options: length, charset (alphanumeric, hex, binary, etc.), capitalization, and even readable formats.
// Highly configurable
const readable = randomstring.generate({
length: 12,
readable: true,
capitalization: 'lowercase'
});
const hex = randomstring.generate({
length: 16,
charset: 'hex'
});
All three work in both Node.js and modern browsers, but their bundle impact differs.
crypto-random-string: Small and tree-shakable. Relies on environment-provided crypto APIs; bundlers polyfill automatically if needed.nanoid: Extremely lightweight (~130 bytes minified). Ships separate browser and Node.js entry points. Optimized for size and speed.randomstring: Larger due to extensive options. May include unused code if you only need basic functionality.For frontend-heavy apps where bundle size matters (e.g., SPAs), nanoid often wins. For server-side token generation, any will do — but simplicity favors crypto-random-string.
You need a long, unpredictable, secure string.
// crypto-random-string (ideal)
const token = cryptoRandomString({ length: 64 });
// nanoid (acceptable, but shorter by default)
const token = nanoid(64); // Override length
// randomstring (fine, but overkill)
const token = randomstring.generate(64);
✅ Best: crypto-random-string — purpose-built for this.
You want short, URL-safe, collision-resistant IDs.
// nanoid (perfect fit)
const id = nanoid(); // 21 chars, base62
// crypto-random-string (requires config)
const id = cryptoRandomString({ length: 21, characters: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' });
// randomstring (verbose)
const id = randomstring.generate({
length: 21,
charset: 'alphabetic'
}); // Not URL-safe by default!
✅ Best: nanoid — designed exactly for this scenario.
You need something like “k9mL2p” that’s easy to read aloud.
// randomstring excels here
const code = randomstring.generate({
length: 6,
readable: true,
charset: 'alphanumeric'
});
// nanoid and crypto-random-string can’t do "readable" out of the box
✅ Best: randomstring — only one with built-in readability.
| Concern | crypto-random-string | nanoid | randomstring |
|---|---|---|---|
| Security Guarantee | ✅ Strictly crypto-only | ✅ Secure by default | ⚠️ Secure by default, but configurable to be insecure |
| API Simplicity | ✅ Minimal, focused | ✅ Ultra-simple default | ❌ Many options |
| Bundle Size | ✅ Small | ✅✅ Tiny | ❌ Larger |
| Readability Support | ❌ No | ❌ No | ✅ Yes |
| Best For | Secrets, tokens, nonces | Short IDs, slugs, keys | User-facing codes, testing |
crypto-random-string. It’s narrow in scope but bulletproof.nanoid is fast, tiny, and purpose-built.randomstring provides the flexibility — just avoid overriding the PRNG.All three are actively maintained and safe to use when applied correctly. The key is matching the tool to your actual need — don’t use a Swiss Army knife when a scalpel will do.
Choose crypto-random-string when you need cryptographically secure random strings for security-sensitive operations like password reset tokens, API keys, or session identifiers. It enforces secure entropy sources and avoids any fallback to insecure randomness, making it the safest choice for secrets. Its minimal API reduces configuration errors, though it lacks features like human-readable output.
Choose nanoid when you need short, unique, URL-safe identifiers for things like database keys, file names, or public slugs. It’s extremely lightweight, fast, and designed specifically for ID generation with zero dependencies. While secure by default, it’s less suited for long secret tokens or human-readable strings.
Choose randomstring when you require fine-grained control over character sets, capitalization, or human-readable formatting (e.g., for user-facing codes or testing fixtures). It supports secure randomness by default but allows insecure configurations if misused, so stick to defaults for security-critical use. Its larger API surface makes it less ideal for simple ID or token generation.
Generate a cryptographically strong random string
Can be useful for creating an identifier, slug, salt, PIN code, fixture, etc.
Works in Node.js and browsers.
npm install crypto-random-string
import cryptoRandomString from 'crypto-random-string';
cryptoRandomString({length: 10});
//=> '2cf05d94db'
cryptoRandomString({length: 10, type: 'base64'});
//=> 'YMiMbaQl6I'
cryptoRandomString({length: 10, type: 'url-safe'});
//=> 'YN-tqc8pOw'
cryptoRandomString({length: 10, type: 'numeric'});
//=> '8314659141'
cryptoRandomString({length: 6, type: 'distinguishable'});
//=> 'CDEHKM'
cryptoRandomString({length: 10, type: 'ascii-printable'});
//=> '`#Rt8$IK>B'
cryptoRandomString({length: 10, type: 'alphanumeric'});
//=> 'DMuKL8YtE7'
cryptoRandomString({length: 10, characters: 'abc'});
//=> 'abaaccabac'
Returns a randomized string. Hex by default.
Returns a promise which resolves to a randomized string. Hex by default.
For most use-cases, there's really no good reason to use this async version. From the Node.js docs:
The
crypto.randomBytes()method will not complete until there is sufficient entropy available. This should normally never take longer than a few milliseconds. The only time when generating the random bytes may conceivably block for a longer period of time is right after boot, when the whole system is still low on entropy.
In general, anything async comes with some overhead on it's own.
import {cryptoRandomStringAsync} from 'crypto-random-string';
await cryptoRandomStringAsync({length: 10});
//=> '2cf05d94db'
Type: object
Required
Type: number
Length of the returned string.
Type: string
Default: 'hex'
Values: 'hex' | 'base64' | 'url-safe' | 'numeric' | 'distinguishable' | 'ascii-printable' | 'alphanumeric'
Use only characters from a predefined set of allowed characters.
Cannot be set at the same time as the characters option.
The distinguishable set contains only uppercase characters that are not easily confused: CDEHKMPRTUWXY012458. It can be useful if you need to print out a short string that you'd like users to read and type back in with minimal errors. For example, reading a code off of a screen that needs to be typed into a phone to connect two devices.
The ascii-printable set contains all printable ASCII characters: !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ Useful for generating passwords where all possible ASCII characters should be used.
The alphanumeric set contains uppercase letters, lowercase letters, and digits: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789. Useful for generating nonce values.
Type: string
Minimum length: 1
Maximum length: 65536
Use only characters from a custom set of allowed characters.
Cannot be set at the same time as the type option.