npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

miniature-id

v1.0.0

Published

A tiny, dependency-free library for generating short, readable, configurable IDs using cryptographically secure randomness.

Readme

miniature-id

A tiny, dependency-free library for generating short, readable, configurable IDs using cryptographically secure randomness.

Not a UUID replacement. Not a NanoID clone. A simple, ergonomic ID generator.

import { tinyId } from "miniature-id";

tinyId(); // "kA9xmP"

Formerly published as tiny-id. Same library, same API, new name.

v1.0.0 is a breaking change: minimum supported runtime is now Node.js 24+ (previously 18+). If you're on an older Node version, stay on 0.1.0 instead. See Runtime Support for why.

Why miniature-id?

Most projects don't need a UUID's 36 characters or a full spec implementation — they need a short, unique-enough, URL-safe string for a user ID, session token, or database key. miniature-id does exactly that, plus a few genuinely useful extras, and nothing else:

  • Tiny. Core is ~1.4 KB minified + brotli; the optional words()/emoji() extras live in a separate subpath so they never cost you anything unless you import them.
  • Zero dependencies. Nothing to audit, nothing to break.
  • Secure by default. Always uses crypto.getRandomValues — never Math.random().
  • Correct. Rejection sampling avoids the modulo bias that a naive byte % alphabet.length implementation would introduce.
  • Cross-runtime. Node.js, Bun, Deno, Cloudflare Workers, Vercel Edge, browsers, Electron.
  • Small, typed API. One core function, five presets, batch generation, and two optional "fun" generators.

If you need collision-probability guarantees, parsing/validation, or a specific ID spec (UUID, ULID, CUID), those are explicitly out of scope here — see FAQ.

Installation

npm install miniature-id

Quick Start

import { tinyId } from "miniature-id";

tinyId(); // "kA9xmP"
tinyId({ length: 12 }); // "aK93Pm2LxQ8r"
tinyId({ prefix: "usr_" }); // "usr_jK92Px"
tinyId({ alphabet: "ABC123" }); // "A1C2B3"
tinyId({ human: true }); // avoids 0/O, 1/I/l, 5/S, 8/B

API

tinyId(options?)

Generates a random ID as a string.

tinyId(options?: TinyIdOptions): string

Options

| Option | Type | Default | Description | | ---------- | --------- | -------------- | ---------------------------------------------------------------------------------------- | | length | number | 6 | Number of characters (not counting prefix/suffix). Must be a non-negative integer. | | alphabet | string | A-Z a-z 0-9 | Custom character set. Duplicate characters are ignored. Overrides human. | | prefix | string | "" | Prepended to the result. | | suffix | string | "" | Appended to the result. | | human | boolean | false | Omits visually confusing characters. Ignored if alphabet is set. |

interface TinyIdOptions {
  length?: number;
  alphabet?: string;
  prefix?: string;
  suffix?: string;
  human?: boolean;
}

Human mode removes characters that are easily confused with one another in many fonts:

| Removed | Because it looks like | | ------------- | ------------------------------ | | 0, O | zero / letter O | | 1, I, l | one / capital I / lowercase L | | 5, S | five / letter S | | 8, B | eight / letter B |

tinyId({ human: true }); // "ktxrGqPn"

Presets

import { short, medium, long, hex, numeric } from "miniature-id";

short(); // 6 chars,  A-Z a-z 0-9  — e.g. "R8ikRY"
medium(); // 12 chars, A-Z a-z 0-9  — e.g. "gPN68gLjox5Z"
long(); // 21 chars, A-Z a-z 0-9  — e.g. "tLDYEZajRQ6rjHskxOERL"
hex(); // 12 hex chars           — e.g. "971bacf8e561"
numeric(); // 8 digits               — e.g. "63689229"

Every preset accepts the same options as tinyId() to override its defaults — e.g. hex({ length: 8, prefix: "req_" }).

Presets (and batch, below) are also attached to tinyId for convenience:

tinyId.short();
tinyId.hex();
tinyId.batch(5);

Prefer the named exports for smaller bundles. import { hex } from "miniature-id" lets a bundler drop everything else you don't use; tinyId.hex() pulls in the whole tinyId object and all attached methods, since they're properties on it.

batch(count, options?)

Generates count IDs in one call.

import { batch } from "miniature-id";

batch(5); // ["kA9xmP", "Zq3rTb", "aK93Pm", "xR2vLn", "Qw81Zk"]
batch(3, { prefix: "usr_", length: 8 });
batch(100, { unique: false }); // skip the uniqueness guarantee, for speed

By default every ID in the result is unique — collisions are retried automatically. If count is impossible for the given alphabet/length (e.g. batch(1000, { alphabet: "AB", length: 1 }), where only 2 unique IDs can ever exist), batch() throws immediately with a clear message instead of retrying forever.

interface BatchOptions extends TinyIdOptions {
  unique?: boolean; // default: true
}

miniature-id/fun — optional extras

Two playful generators, kept in a separate subpath so they don't add a single byte to the core bundle unless you actually import them:

import { words, emoji } from "miniature-id/fun";

words(); // "brave-otter-42"
words({ separator: "_", numberLength: 0 }); // "swift_falcon"
emoji(); // "🦊🌙🍄"
emoji({ length: 6 });

words() draws from a small, hand-curated list (64 adjectives x 64 nouns) plus an optional trailing number for extra uniqueness — good for things like container names, feature branches, or temporary environment labels. It is not meant for high-volume or security-sensitive IDs: the keyspace is small (~410,000 combinations with the default 2-digit number) compared to tinyId()'s alphanumeric output. Use a longer numberLength, or switch to tinyId()/a preset, if that matters for your case.

emoji() draws from a curated set of 32 neutral emoji (animals, plants, simple symbols — no faces, gestures, or flags) — fun for avatars, reaction IDs, or party codes, but not recommended anywhere the ID needs to be typed, sorted, or stored in a system with shaky emoji support.

interface WordsOptions {
  separator?: string; // default: "-"
  numberLength?: number; // default: 2 (0 disables the trailing number)
  prefix?: string;
  suffix?: string;
}

interface EmojiOptions {
  length?: number; // default: 3
  prefix?: string;
  suffix?: string;
}

Examples

// A user ID
tinyId({ prefix: "usr_", length: 10 }); // "usr_kA9xmPQz3r"

// A short-lived token
tinyId({ length: 24 });

// A human-readable invite code (no confusing characters)
tinyId({ human: true, length: 8 }).toUpperCase(); // e.g. "KTXRGQPN"

// A request ID
hex({ prefix: "req_" }); // "req_971bacf8e561"

// A batch of unique coupon codes
batch(50, { human: true, length: 10 });

// A friendly container name
words(); // "calm-heron-19"

Runtime Support

| Runtime | Supported | Notes | | ------------------- | :-------: | -------------------------------------------------------------------------- | | Node.js 24+ | ✅ | Uses globalThis.crypto.getRandomValues natively — no fallback needed. | | Bun | ✅ | | | Deno | ✅ | | | Cloudflare Workers | ✅ | | | Vercel Edge | ✅ | | | Browsers | ✅ | Any browser with window.crypto.getRandomValues (all modern browsers). | | Electron | ✅ | |

Node.js 24 is the minimum supported version as of v1.0.0. Every runtime above exposes globalThis.crypto.getRandomValues natively, so there's a single, simple code path with no fallback logic and no environment-specific workarounds required.

Upgrading from 0.1.0? That version additionally supported Node.js 18–23, via a node:crypto fallback for environments without globalThis.crypto. That fallback (and the runtimes it existed for) has been removed entirely in v1.0.0 — if you're on Node.js 18–23, stay on 0.1.0, or upgrade Node.

TypeScript

miniature-id is written in TypeScript and ships its own types — no @types package needed.

import { tinyId, type TinyIdOptions } from "miniature-id";

const opts: TinyIdOptions = { length: 10, human: true };
tinyId(opts);

FAQ

How long should my ID be? Longer IDs have a lower collision probability. As a rough guide: the built-in long() preset (21 characters over a 62-character alphabet) is the same length nanoid defaults to, chosen for very low collision odds at high volumes. If you need a precise collision-probability calculation for your exact alphabet/length/volume, that's outside this library's scope — plenty of birthday-problem calculators exist online.

Why not use UUIDs? UUIDs are a great, standardized choice, especially if you need interoperability with systems that expect that specific format. miniature-id exists for cases where you want something shorter and more readable, and don't need the UUID spec itself.

Does miniature-id validate or parse IDs it generates? No — that's explicitly out of scope. miniature-id only generates strings; it doesn't validate format, decode metadata, or guarantee cross-call uniqueness (except within a single batch() call, when unique: true).

Can I use miniature-id for security tokens (e.g. password reset links)? miniature-id always uses a cryptographically secure random source, so the randomness itself is appropriate for that use case. Whether the length and alphabet you choose give enough entropy for your threat model is a judgment call you should make deliberately — longer is safer. Stick to tinyId()/the numeric presets for this; words()/emoji() have a much smaller keyspace and are not intended for anything security-sensitive.

Why is tinyId.hex() bigger than import { hex }? See Presets above — it's a deliberate tree-shaking trade-off, not a bug.

What happened to tiny-id? This library was previously published as tiny-id. It's been renamed to miniature-id (the tiny-id name is no longer maintained under this project). The API is unchanged aside from the new additions documented here.

Security Notes

  • miniature-id only uses cryptographically secure randomness (globalThis.crypto.getRandomValues) — never Math.random().
  • Character selection uses rejection sampling, not byte % alphabet.length, to avoid modulo bias (some characters being subtly more likely than others). This matters most for alphabet sizes that aren't a power of two — which is most custom alphabets, including the default 62-character one. The same rejection-sampling guarantee applies to words()/emoji()'s list selection.
  • This library makes no collision-probability guarantees, except within a single batch() call when unique: true (the default). Longer IDs and larger alphabets reduce collision risk; you're responsible for choosing parameters appropriate to your use case and expected volume.
  • This library does not implement any specific security-token spec (e.g. CSRF tokens, session IDs) — it generates random strings, which you can use as a building block for those.

Bundle Size & Performance

Minified + brotli:

| Import | Size (approx.) | | ------------------------------------------------- | ---------------: | | import { tinyId } from "miniature-id" | ~1.4 KB | | Everything from the core (tinyId + all presets + batch) | ~1.4 KB | | import { words, emoji } from "miniature-id/fun" | ~1.7 KB |

Rough throughput comparison (ops/sec, single machine, not a rigorous benchmark — see benchmark/benchmark.mjs):

| Library | ops/sec (approx.) | | --------------------------------- | ------------------: | | tinyId() (6 chars) | ~4,200,000 | | tinyId({ length: 21 }) | ~1,500,000 | | uuid (uuidv4()) | ~4,850,000 | | crypto.randomUUID() | ~5,600,000 | | nanoid() | ~22,000,000 |

miniature-id is in the same ballpark as uuid/crypto.randomUUID(), and slower than nanoid, which uses a more aggressively optimized internal pooling strategy. For the vast majority of applications (generating IDs in response to user actions, not in a tight hot loop), this difference is not meaningful — but we'd rather show the real numbers than claim to be "faster" without evidence.

License

MIT