Library / SDK
sindresorhus/crypto-random-string avatar
sindresorhus/crypto-random-string

crypto-random-string: a cryptographically strong string in one call

Generate a cryptographically strong random string

591 stars43 forksJavaScriptMIT

At a glance

What is it?
crypto-random-string is a tiny ESM package that generates cryptographically strong random strings from seven predefined alphabets or from a character set you supply, with no dependencies beyond a type helper and a byte utility. It suits identifier, slug, salt, PIN and fixture generation in Node and the browser, and it is not a key derivation function and cannot be seeded.
Who is it for?
Adopt crypto-random-string when you need a random identifier, slug, salt, PIN or fixture string and you would rather not assemble a character set and call the crypto API yourself. Do not adopt it for password hashing, key derivation or anything that needs to be reproducible, since it produces fresh randomness on every call and offers no seed.
Can I use it commercially?
Yes. MIT 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 35 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One function, seven predefined alphabets

crypto-random-string generates a cryptographically strong random string, and the README gives the intended uses straight away: creating an identifier, a slug, a salt, a PIN code or a fixture. It works in Node.js and in browsers.

The API is one function with one options object. The length option is required and is a non-negative integer, and the type option picks the alphabet, defaulting to hex:

js
import cryptoRandomString from 'crypto-random-string';

cryptoRandomString({length: 10});
//=> '2cf05d94db'

cryptoRandomString({length: 10, type: 'base64'});
//=> 'YMiMbaQl6I'

cryptoRandomString({length: 10, type: 'url-safe'});
//=> 'YN-tqc8pOw'

The accepted type values are hex, base64, url-safe, numeric, distinguishable, ascii-printable and alphanumeric. The url-safe set is the one to notice for identifiers, because it avoids the characters that have to be escaped in a URL or a slug, and the alphanumeric set is documented as useful for generating nonce values.

Everything is driven from the same place, so the difference between a hex token and a PIN is one string in the options object rather than a different function or a different import.

The package is published as crypto-random-string on npm at version 6.0.0, and it is an ESM only package with the type set to module, exports pointing at index.js with the types at index.d.ts, sideEffects false, and a node requirement of 22 or newer. The runtime dependencies are type-fest for the option types and uint8array-extras for the byte handling, which is a short dependency list for a security relevant package.

The type option and the characters option exclude each other

The second way to choose the alphabet is the characters option, a string of the characters you want to draw from, with a minimum length of 1 and a maximum length of 65536. The example in the README shows a custom set of three characters producing a string from that set:

js
cryptoRandomString({length: 10, characters: 'abc'});
//=> 'abaaccabac'

The important rule is that characters and type cannot be set at the same time, and the documentation states it in both directions. That is not a technical limitation that happens to be enforced, it is a statement about which of the two you meant. A caller who passes both has said two contradictory things, and the package refuses rather than guessing.

One property of the custom set is worth internalising, because it is the kind of thing that quietly weakens a token. Each character is picked with equal probability, so repeating a character in the set makes it more likely to be picked. The example above shows it directly: an alphabet of three characters produces a string in which one of them is visibly more frequent, and the effective entropy of the string is lower than the length suggests.

So a custom set is the right tool when the alphabet is a business rule, such as a set of allowed characters for a legacy system, and the wrong tool when you are trying to express a strength requirement, where the predefined sets have already been thought about.

The distinguishable set trades entropy for human typing

The distinguishable type is the one that shows the package thinking about the interface rather than only the cryptography. The set contains only uppercase characters that are not easily confused: CDEHKMPRTUWXY012458.

The stated use case is a short string that you would like users to read and type back in with minimal errors, and the example given is a code read off a screen that has to be typed into a phone to connect two devices. The characters are chosen to remove the pairs that people confuse: no zero and no letter O, no one and no letter I, no five and no letter S.

The trade-off is arithmetic and it is worth stating plainly. The distinguishable set has eighteen characters, while the default hex set has sixteen and base64 has sixty four, so a six character distinguishable code has a far smaller search space than a six character hex string. That is a deliberate design decision for a human-facing code, not a defect, but it means the type is not interchangeable with the other alphabets when the string is a secret rather than a code to be read aloud.

The ascii-printable set takes the opposite approach and includes all printable ASCII characters except the space, which the documentation suggests for generating passwords where all possible ASCII characters should be used. The alphanumeric set is the most conventional of the three, containing uppercase letters, lowercase letters and digits, and it is the one to reach for when the consumer is a system rather than a person.

Length is counted in characters, and that includes emoji

There is a subtlety in the length option that the documentation spells out, and it is the kind of detail that causes an off by one bug in a token generator.

The length is the number of characters, so a string generated from a characters set that contains characters outside the Basic Multilingual Plane, such as emoji, has a larger .length than the number you asked for. The reason is that JavaScript string length counts UTF-16 code units, while the package counts Unicode characters, and an emoji outside the Basic Multilingual Plane needs two code units in UTF-16.

The limits themselves are handled in the right way, though. The minimum length of the characters option is 1 and the maximum is 65536, and the documentation notes that those length limits count Unicode characters and not UTF-16 code units, so characters outside the Basic Multilingual Plane are handled correctly.

The practical consequence is that if you are generating a token whose length must be measured in bytes, for instance because it is written into a fixed width database column or a header with a byte limit, you should measure the byte length yourself rather than trusting the length option. The package is explicit about the character semantics and does not claim to give you bytes.

For the default hex alphabet, none of this matters, since every character is one code unit and one byte, which is the reason the default is a sensible one for identifiers.

Where crypto-random-string is the wrong tool

Three limits follow from what the package is.

The first is that it generates, it does not derive. There is no key derivation function here, no password hashing, and no stretching of a user supplied secret. If you need a value that is derived from a password, this is the wrong package, and a password hashing function is a different category of tool with a different threat model.

The second is that there is no seed. Every call produces fresh randomness, which is exactly what you want for a salt and exactly what you do not want for a test fixture that has to be identical on every run. The README lists fixtures among the use cases, and for a fixture the more usual approach is a fixed literal in the test file.

The third is the browser and Node split, which is a strength but also a boundary. The package works in both, and it ships as an ESM only package requiring node 22 or newer, so a CommonJS project on an older runtime cannot consume it without changing its module system. The type declarations are shipped in the package, and the type tests are part of the test script, which is the kind of care that makes the option object usable in a typed codebase.

For a project that needs a random string, the alternative is to assemble it yourself from crypto.getRandomValues or node:crypto, choosing an alphabet and encoding it. The difference in approach is that this package encodes the choice for you, including the human readability set that is easy to get wrong, and it does so in about a page of code.

Editorial conclusion

Adopt crypto-random-string when you need a random identifier, slug, salt, PIN or fixture string and you would rather not assemble a character set and call the crypto API yourself. Do not adopt it for password hashing, key derivation or anything that needs to be reproducible, since it produces fresh randomness on every call and offers no seed. Verify first that the alphabet you choose suits the consumer of the string, particularly whether the distinguishable set is acceptable for a security use given how much smaller it is than the default hex set, and that your runtime satisfies the node 22 requirement.

Frequently asked questions

How do I install crypto-random-string?

Run npm install crypto-random-string. It is an ESM only package that requires node 22 or newer, and it works in Node.js and in browsers.

Which character sets does crypto-random-string support?

The type option accepts hex, base64, url-safe, numeric, distinguishable, ascii-printable and alphanumeric, and it defaults to hex. It cannot be combined with the characters option, which takes a custom set of allowed characters instead.

What is the distinguishable type for?

The distinguishable set contains only uppercase characters that are not easily confused, CDEHKMPRTUWXY012458, and it is meant for short strings a person has to read off a screen and type back in with minimal errors, such as a code that pairs two devices.

Can I use crypto-random-string to generate a password hash?

No. It generates random strings from a cryptographically strong source, it does not derive a value from a secret and it does not hash. A password hashing function is a different tool with a different threat model.

How does crypto-random-string count length for emoji characters?

The length option counts Unicode characters, not UTF-16 code units, so a string built from characters outside the Basic Multilingual Plane has a larger .length than the number requested. The limits on the characters option are counted the same way.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. Releases
  5. sindresorhus/crypto-random-string on GitHub
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/sindresorhus-crypto-random-string.svg)](https://hysenlabs.com/projects/sindresorhus-crypto-random-string)

Was this useful?