stable-hash
Tiny, fast library for stably hashing any JavaScript value
Repository Health
Technical Analysis
stable-hash is a tiny (under 500 bytes) utility for producing a deterministic hash of any JavaScript value, including types that JSON.stringify cannot handle like BigInt, NaN, Symbol, functions, and classes. It was originally created for SWR to derive stable cache keys from arbitrary arguments.
Unlike JSON.stringify, stable-hash sorts object keys so that two objects with the same properties in different orders hash identically, and it safely handles circular references using a WeakMap-backed identity table. The result is not a serialization format or a cryptographically secure checksum — it is a fast, consistent fingerprint intended for cache keys, memoization, and equality checks.
What You Get
- A single default export function that hashes any JavaScript value to a string
- Deterministic key ordering for objects, so equivalent objects always hash the same
- Support for BigInt, NaN, Symbol, functions, classes, Date, RegExp, Set, and Map
- Circular reference detection via an internal WeakMap-based identity table
- A near-zero dependency footprint and sub-500-byte minified bundle size
Common Use Cases
- Deriving stable cache keys for data-fetching libraries like SWR
- Memoizing expensive computations based on complex argument shapes
- Comparing two arbitrary values for structural equality without a full deep-equal implementation
- Deduplicating requests or events keyed by non-trivial argument objects
Under The Hood
Architecture - The entire library is a single exported function, stableHash, in src/index.ts. It branches on the value’s type and constructor: primitives and dates/regexes are stringified directly, while plain objects and arrays are recursively walked with keys sorted (Object.keys(arg).sort()) before concatenation, and any other object (Set, Map, function, class) is assigned an incrementing counter-based id. A module-level WeakMap<object, string> records each object’s assigned hash the moment recursion begins, so a circular reference resolves to its own in-progress hash instead of recursing forever.
Tech Stack - Written in TypeScript, built with esbuild to both CJS and ESM outputs plus a separate tsc --emitDeclarationOnly pass for .d.ts files, and tested with Jest via ts-jest. There are no runtime dependencies at all; devDependencies are limited to the build/test toolchain and a handful of comparison libraries (hash-obj, json-stringify-deterministic, flattie) used only in benchmarks.
Code Quality - The tests/ directory exercises primitives, BigInt, Symbol, Date, RegExp, arrays, objects (including circular and key-order cases), and reference-type consistency for functions/classes/Set/Map, giving good coverage for a single-function library. The source itself is compact (under 60 lines) with inline comments explaining the WeakMap technique and non-obvious branches; there is no external type validation since the function intentionally accepts any.
API Design - The API surface is a single default export taking one argument and returning a string, which makes adoption essentially zero-friction. The README is thorough for the library’s size, documenting behavior for every supported type with runnable examples, and it is explicit about what the function does NOT guarantee (not a serialization format, not cryptographically secure), which sets correct expectations for consumers.
Used by 2 apps in this directory
agenta
Developer Tools · Devops · AI Development
The open-source LLMOps platform unifying prompt engineering, evaluation, and observability for teams building reliable LLM applications.
Jitsu
Data Engineering
Open-source, fully-scriptable data ingestion engine that streams events from web, apps, and APIs to any data warehouse in real time.