dev101.io

NanoID Generator

Generate URL-safe unique IDs with configurable length and alphabet.

Loading tool…

How to use NanoID Generator

  1. Pick a length with the slider — the default is 21 characters, which matches the reference `nanoid` package and gives 126 bits of entropy.
  2. Choose an alphabet preset from the dropdown. URL-safe (64 chars) is the best default; switch to Numbers-only for short numeric codes, No-look-alike for IDs humans will read aloud, or Custom to paste your own characters (Unicode and emoji supported).
  3. Set the count to generate 1, 5, 10, 25, 50, or 100 IDs at once. Counts up to 10 regenerate live as you tweak settings; larger batches wait for a Regenerate click.
  4. Optionally add a prefix (like `user_`) and a suffix — useful when you want identifiers that look like `user_V1StGXR8_Z5jdHi6B-myT.v1`.
  5. Press Regenerate (or ⌘/Ctrl + Enter) to mint a fresh batch. The entropy and collision-year chips at the top of the output panel always reflect the current settings.
  6. Click the per-row Copy button to grab one ID, or Copy all to put the whole list on the clipboard in one shot.
  7. Use the Share button to persist your option state in the URL — the generated IDs themselves are deliberately NOT encoded, so the link gives a teammate your recipe, not your secrets.

NanoID Generator

A compact, URL-safe, cryptographically-secure unique identifier minted entirely in your browser. Every byte of entropy comes from crypto.getRandomValues, every character is drawn via bit-mask rejection sampling — the same algorithm the reference nanoid npm package uses — and nothing ever leaves the page. No network call, no analytics on the textarea, no dependencies pulled into the bundle just to produce 21 random characters.

Why a dedicated NanoID tool

NanoID is one of those utilities everyone needs twice a year and nobody wants to install. The reference npm package is tiny but still a dependency and a lockfile churn; online generators often run on the public internet with a log file under the hood; and the DIY "just use crypto.getRandomValues" approach usually gets the rejection-sampling step wrong, leaving a subtle modulo bias that skews the output distribution. The NanoID generator on dev101.io is the opposite of all of that: a single-page client-side tool with zero new runtime dependencies, a transparent implementation you can read in one sitting, and a visible entropy / collision-year readout so you can actually see what each setting buys.

The tool also covers the scenarios the nanoid package itself requires extra imports for: human-readable no-look-alike alphabets (drops 0, O, 1, I, l), Unicode alphabets including emoji, prefix/suffix wrapping for typed namespaces like user_…, and bulk generation up to 100 IDs in a single click. The output panel gives each ID its own copy button plus a Copy all action, and the live-preview mode regenerates as you tweak settings so you can zero in on a format without three round-trips through the Regenerate button.

What it does

  • CSPRNG-backed core. Every random byte is drawn from crypto.getRandomValues, the W3C Web Crypto primitive implemented natively against the OS entropy pool on every modern browser and on Node.js. No Math.random anywhere; see Why Math.random is unsafe below.
  • Bit-mask rejection sampling. The generator computes the smallest (2^k - 1) mask such that 2^k ≥ alphabet_size, fills a random buffer, and rejects masked bytes ≥ alphabet size. This is the same algorithm as the reference nanoid package, and it provably removes the modulo bias that a naive bytes[i] % N implementation leaves in place.
  • 21-character URL-safe default. 64-char alphabet (A-Z, a-z, 0-9, _, -) gives 126 bits of entropy per ID — comfortably past UUID v4's 122 bits in a 15-character-shorter string with no hyphens.
  • Alphabet presets. URL-safe, numbers-only, lowercase alphanumeric, uppercase alphanumeric, lowercase letters, uppercase letters, no-look-alike (drops 0, O, 1, I, l), hex-lowercase, and a fully custom field for your own characters.
  • Unicode + emoji support. Custom alphabets are parsed as code points, not UTF-16 units, so 🍎🍌🍊🍇 is a valid 4-character alphabet and a length-6 ID from that pool is exactly 6 emoji.
  • Prefix / suffix wrapping. Decorate the random core with user_… or …_test so the final identifier reads as part of your domain language. Prefix and suffix do not count toward the length setting.
  • Bulk generation 1-100. Pick 1, 5, 10, 25, 50, or 100 IDs per batch with chip buttons. Under-10 batches regenerate live as settings change.
  • Live entropy + collision readout. Two chips at the top of the output panel show the Shannon entropy per ID (log2(alphabet_size) * length) and a birthday-bound estimate of "years until a collision becomes likely at 1000 IDs/sec". Shortening the length or narrowing the alphabet visibly moves the numbers.
  • Keyboard-first workflow. ⌘/Ctrl + Enter regenerates; each row has its own Copy button; the Copy all action hands the full list to the clipboard.

How the rejection-sampling core works

A naive "pick a character from an alphabet of size N" implementation is charset[bytes[i] % N]. When N doesn't divide 256 evenly — for example N = 10 — the first 256 mod N characters (the first 6 digits, in this case) come out slightly more probable than the last four. Over enough IDs this skews the distribution and reduces the effective entropy below the advertised log2(N) * length figure.

The fix is bit-mask rejection sampling. For a given N, compute the smallest k with 2^k ≥ N and use mask = 2^k - 1. Fill a random buffer, mask each byte, and accept the result only if the masked value is less than N — otherwise redraw. The acceptance probability is N / 2^k, which for typical alphabets is 50% to 100%. The discarded portion maps 1:1 to values ≥ N; dropping them leaves a provably uniform distribution over [0, N).

The implementation sizes the random buffer to produce roughly length accepted characters per refill, with a 1.6× safety margin so the refill loop fires rarely. The test suite includes a chi-square goodness-of-fit check over 10,000 digits against the numbers-only alphabet (N = 10, the classic non-power-of-two case) that flags any regression.

Privacy and trust

Everything runs locally. Generation, alphabet validation, entropy calculation, and clipboard copy all happen inside the React component. There is no API endpoint invoked. There is no analytics script observing the textarea. There are no third-party scripts anywhere on the page. Open the browser devtools Network tab, click Regenerate fifty times, and the request list stays empty.

No NanoID is ever persisted. The generated IDs live in React component state, nowhere else. They are not written to localStorage, sessionStorage, IndexedDB, the URL hash, query string, or cookies. Reloading the tab destroys them. The Share button serialises your option preferences into the URL fragment so a teammate can reproduce your setup; it deliberately does not include the generated IDs themselves.

No Math.random. JavaScript's Math.random is a fast linear pseudo-random generator seeded from a low-entropy source, with internal state that can often be recovered from a small handful of outputs. Using it for id generation on a security boundary is a known anti-pattern. This tool uses crypto.getRandomValues exclusively, and the chi-square distribution test is run on every CI build to make sure the rejection-sampling path stays unbiased.

When to reach for UUID v7 instead

NanoID is the right answer when the id is destined for a URL path, a filename, a Redis key, a log line, or anywhere a human might paste or type it. It's compact (21 chars for 126 bits) and it avoids the punctuation that forces downstream escaping.

UUID v7 is the right answer when the id is going to become a primary key on a write-heavy table. A NanoID has no notion of time, so its bits are uniformly distributed across the index — every insert lands in a random leaf of the B-tree, fragmenting the index and inflating write amplification. UUID v7 embeds a 48-bit unix-millisecond timestamp in its leading bits, so inserts append to the right edge of the B-tree and the index stays cache-friendly.

For everything in between — session ids, cache keys, idempotency tokens, request ids on service boundaries — either works and the decision comes down to string-layout preference. Both are crypto.getRandomValues-backed in this toolbox, so neither is "more secure" than the other.

Related tools

  • UUID Generator — when you need an RFC 9562 v1, v4, or v7 identifier, including the time-ordered v7 for database primary keys.
  • Password Generator — CSPRNG-backed passwords and passphrases with entropy scoring, sharing the same rejection-sampling primitive.
  • SHA-256 Hash — when you want a deterministic identifier derived from content instead of entropy.

Frequently asked questions

What is a NanoID and how is it different from a UUID?

A NanoID is a compact, URL-safe, cryptographically-secure unique identifier scheme popularised by the `nanoid` npm package. The default NanoID is 21 characters drawn from a 64-character URL-safe alphabet, carrying 126 bits of entropy — slightly more than the 122 bits in a UUID v4 while being almost 40% shorter as a string. NanoIDs never need hyphens or base64 re-encoding to sit inside a URL path, an HTTP header, a filename, or a JSON key, which is usually the reason teams reach for them in the first place.

Is the generated NanoID safe to use in production?

Yes. Every byte of entropy comes from the Web Crypto API's `crypto.getRandomValues`, which is a cryptographically-secure random number generator implemented against the operating-system entropy pool on every modern browser and on Node.js. The implementation uses bit-mask rejection sampling, the same technique as the reference `nanoid` package, so the character distribution is provably uniform regardless of alphabet size — no modulo bias. Nothing is logged, posted, or persisted; the tool runs entirely in your browser tab.

What is the probability of a collision?

With the default 21-character URL-safe alphabet (64 chars, 126 bits of entropy) you can generate roughly 1000 IDs per second for about 265 million years before the birthday-bound 50% collision probability is reached. For practical purposes the default is collision-free. If you shorten the length or switch to a smaller alphabet such as numbers-only, the safe volume drops dramatically — this tool shows the estimate live so you can see exactly what each choice buys. For user-facing short codes consider 10–12 chars from the 59-char no-look-alike set; for database primary keys keep the default.

Why would I pick NanoID over a UUID v7?

Choose NanoID when the id has to be typed, spoken, scanned, or URL-pasted without escaping. A 21-char NanoID is 15 characters shorter than a 36-char UUID string and contains no hyphens, so it survives being dropped into a URL path, a filename, a Redis key, or a QR code without any normalisation. Choose UUID v7 when you need a time-sortable primary key for a B-tree index — a NanoID has no notion of time and random leading bits will fragment the index. Both use `crypto.getRandomValues` under the hood so neither is "more secure" than the other; pick by string layout and ordering requirements.

Can I use a custom alphabet with emoji or other Unicode characters?

Yes. The custom alphabet field accepts any Unicode input, and the generator treats each code point as exactly one "character" even when it spans two UTF-16 surrogate pair units. So `🍎🍌🍊🍇` is a valid 4-character alphabet and a length-6 ID from that pool is always 6 emoji. Duplicates in the input are removed automatically. Keep in mind that displaying or matching the resulting IDs elsewhere (databases, regex, logs) has to be Unicode-aware too — ASCII-only pipelines will see the UTF-16 units, not the code points.

Does the share link include the generated IDs?

No, by design. The Share button encodes your option state (length, alphabet preset, count, prefix, suffix) into the URL fragment so a teammate can reproduce your settings. The generated IDs themselves are never serialised into the URL, into localStorage, or into any other browser-persisted store. Reloading the tab regenerates fresh IDs from the same settings. This matches the privacy posture of the sibling Password Generator — secret material and random tokens stay in component state only.

Related tools