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

hamsterid

v1.0.1

Published

lexicographically sortable unique identifier generator

Readme

HamsterID

A lexicographically sortable, fixed-length unique identifier generator.

429t78n91cck41njk21rjula6u

Why

  • Sortable as stringsORDER BY id gives chronological order. No separate created_at column needed for ordering.
  • Fixed length — always 26 chars. No leading-zero padding logic, no variable-width surprises in storage or logs.
  • Monotonic — IDs generated in the same process never go backwards. If the random + timer bits would produce a value <= the previous ID, it is bumped by 1. Safe for hot-loop generation.
  • 128 bits — same size as UUID/ULID. Fits in a single bigint or a 16-byte column.
  • No padding, no Crockford alphabet — straight base32 (0-9a-v), so it round-trips through BigInt / parseInt without lookup tables.
  • Sub-millisecond ordering — uses a high-resolution timer (nanoseconds on Node, microseconds in browsers) as part of the value, so two IDs from the same millisecond still sort correctly.
  • Crypto-strong random — uses crypto.getRandomValues when available, falls back to Math.random with a warning.

Install

npm install hamsterid

Quick start

import next from "hamsterid";

next(); // "429t78p7lcefqp8ujjr9k2gntf"
next(); // "429t78p7pcefuvggusflg3k1tp"

IDs from the same process are strictly increasing:

const a = next();
const b = next();
a < b; // true (string comparison)

CLI

Generate IDs from the command line without installing:

npx hamsterid        # one ID
npx hamsterid 5      # five IDs
429t797gbcs3cpc2v00ssl51bu
429t797gdcs3eosr5fgphse0qj
429t797gdcs3eqikgmhojfdpks
429t797gdcs3erav5d2vksml7q
429t797gdcs3errfqn2octkv2g

HamsterID Bit layout

128 bits, laid out most-significant first:

| Field | Bits | Meaning | | --------- | ------------ | ------------------------------------------------------------- | | Fixed 1 | 1 | Guarantees a fixed 26-char base32 length (no leading zeros) | | Timestamp | 42 | Milliseconds since 2024-01-01 UTC (~139 years, until ~2163) | | HR time | 0 / 30 / 40 | Sub-millisecond ordering. Width depends on the runtime | | Random | 85 / 55 / 45 | Collision resistance. Fills whatever the HR-time field didn't |

The HR-time and random widths depend on the environment:

| Runtime | HR-time bits | Random bits | HR-time resolution | | ------------------------- | ------------ | ----------- | ----------------------- | | Node.js | 40 | 45 | 1 nanosecond | | Browsers (Chromium-based) | 30 | 55 | 100 microseconds | | Firefox / Safari | 0 | 85 | n/a (spectre-mitigated) |

When no usable high-resolution timer is available (Firefox/Safari, where performance.now is mitigated), the HR-time field is dropped and the full 85 bits go to random — more collision resistance, same fixed length.

Properties

Lexicographic sortability

Because the most significant bits are the timestamp and the fixed leading 1, string comparison of two base32 IDs matches chronological order:

const ids = Array.from({ length: 1000 }, () => next());
const sorted = [...ids].sort(); // already chronological
sorted[0] === ids[0]; // true

Monotonicity within a process

Each generated ID is compared against the last. If the new value would be <= the previous one (e.g. the clock went backwards or random bits collided), it is replaced with last + 1. This guarantees a strictly increasing sequence within a single process.

Monotonicity is per-process. Across processes/machines, IDs remain sortable by timestamp but are not strictly monotonic.

Uniqueness

The random field plus the monotonic bump makes in-process collisions effectively impossible. Across independent processes generating within the same millisecond, collision probability is governed by the random width (45 / 55 / 85 bits) — the same birthday-bound math as ULID.

Comparison with ULID

| | HamsterID | ULID | | ------------------ | ------------------- | ------------------------------------------ | | Length | 26 chars | 26 chars | | Alphabet | base32 0-9a-v | Crockford base32 | | Sortable as string | yes | yes | | Sub-ms ordering | yes (HR timer) | no (ms only; relies on random for same-ms) | | Monotonic | yes, in-process | only with monotonic factory | | Random source | crypto by default | implementation-defined |

License

MIT