string-hash
string-hash turns a JavaScript string into a deterministic unsigned 32-bit integer. Its entire runtime is one CommonJS function based on a djb2-like loop, with no dependencies or configuration. That makes it useful for repeatable colors, buckets, and other non-security decisions where a compact number matters more than collision resistance. It is not encryption, a password hash, or a safe unique-ID generator.
Keep it for low-stakes deterministic display choices or bucketing in an existing CommonJS app. Do not newly install it for security, identity, TypeScript ergonomics, or any workload where a collision causes damage.
Use it if
- You need the same non-negative 32-bit number every time a given string appears
- You want deterministic UI colors, placeholder choices, or shard buckets without keeping a lookup table
- You maintain CommonJS code and value a one-function package with no runtime dependencies
- Collisions are acceptable and the hash never crosses a security boundary
- You need security: the README describes a djb2-like non-cryptographic algorithm, so it is unsuitable for passwords, signatures, integrity checks, or attacker-controlled keys
- You need unique or durable identifiers: the output is only an unsigned 32-bit integer, so distinct strings can collide and the README promises no collision guarantees
- You require active maintenance: version 1.1.3 was published in 2017, the repository is archived, and its last code push was in 2020
- Your project requires native ESM or bundled TypeScript declarations: the published package exposes only module.exports and contains no types field
- You need hashes for objects, files, streams, or binary data: the implementation accepts a string and iterates with charCodeAt, with no canonicalization or incremental API
Setup reality
Installation is only npm install string-hash, and there are no runtime dependencies, peer dependencies, native builds, environment variables, credentials, or config files. In CommonJS, require('string-hash') returns the function directly. The friction shows up in modern toolchains and in deciding whether the result is fit for purpose. The package has no bundled TypeScript declarations and no ESM export map, so strict TypeScript projects need an ambient declaration such as declare module 'string-hash' or a third-party types package, while native Node ESM relies on CommonJS interop. Inputs must be strings; passing an object does not serialize it, and the implementation reads length and charCodeAt directly. JavaScript strings are UTF-16, so normalization-equivalent Unicode text can hash differently unless you call normalize() first. The return value is a Number from 0 through 4294967295, not a hex string. Most importantly, collisions are an expected consequence of the 32-bit output. Never use the result as proof of equality, as a database uniqueness key, or anywhere an attacker benefits from choosing collisions. The package is archived and has not released since 2017, so there is no credible path for feature requests, ESM support, or bundled types; adopt it only if its frozen, tiny API is exactly what you want.
Patterns
Hash a string to an unsigned integerhash-string
const stringHash = require('string-hash');
const value = stringHash('Hello, world!');
console.log(value); // 343662184The result is a JavaScript Number in the unsigned 32-bit range, not a cryptographic digest.
Assign a stable bucketassign-bucket
const stringHash = require('string-hash');
function bucketFor(userId, bucketCount) {
if (!Number.isInteger(bucketCount) || bucketCount < 1) throw new RangeError('bucketCount');
return stringHash(userId) % bucketCount;
}
console.log(bucketFor('user-42', 16));Changing bucketCount reshuffles many values; use rendezvous or consistent hashing when stable rebalancing matters.
Make a repeatable rollout decisionpercentage-rollout
const stringHash = require('string-hash');
function isEnabled(flag, userId, percent) {
const slot = stringHash(`${flag}:${userId}`) % 100;
return slot < Math.max(0, Math.min(100, percent));
}
if (isEnabled('new-nav', 'user-42', 10)) showNewNav();This is deterministic allocation, not tamper resistance; do not trust a client-computed result for authorization.
Choose a deterministic palette colorpick-color
const stringHash = require('string-hash');
const palette = ['#2563eb', '#7c3aed', '#db2777', '#ea580c'];
function colorFor(label) {
return palette[stringHash(label) % palette.length];
}
console.log(colorFor('Ada Lovelace'));Different labels can select the same color by design; this is a display mapping, not an identity check.
Select a repeatable placeholderpick-placeholder
const stringHash = require('string-hash');
const placeholders = ['/avatar-1.svg', '/avatar-2.svg', '/avatar-3.svg'];
const placeholderFor = (key) => placeholders[stringHash(key) % placeholders.length];
img.src = placeholderFor(account.email);Hashing an email does not anonymize it; avoid exposing the numeric hash as if it protected personal data.
Normalize Unicode before hashingnormalize-unicode
const stringHash = require('string-hash');
function hashVisibleText(text) {
return stringHash(text.normalize('NFC'));
}
console.log(hashVisibleText('café'));Visually identical text can have different UTF-16 sequences; normalization makes canonical equivalents agree.
Hash a structured pair without ambiguous joinshash-composite-key
const stringHash = require('string-hash');
function hashPair(left, right) {
return stringHash(JSON.stringify([left, right]));
}
console.log(hashPair('team:blue', 'member:7'));JSON encoding avoids delimiter ambiguity, but the final 32-bit value can still collide.
Format the result as fixed-width hexadecimalformat-hex
const stringHash = require('string-hash');
const hex = stringHash('invoice-42').toString(16).padStart(8, '0');
console.log(hex);Hex changes only the display format; it does not add entropy or make the algorithm cryptographic.
Use a hash as a quick check, then compare originalsverify-with-original
const stringHash = require('string-hash');
function probablySame(a, b) {
if (stringHash(a) !== stringHash(b)) return false;
return a === b;
}
console.log(probablySame('alpha', 'alpha'));A matching hash is not proof of equality, so collision-sensitive code must compare the original values too.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| imurmurhash | npm | You want incremental MurmurHash3 and may receive a value in chunks |
| hash-sum | npm | You need a short deterministic hash for JavaScript values and objects, not only strings |
| object-hash | npm | You need configurable hashing of objects with documented serialization behavior |
| crypto-js | npm | You need standard cryptographic digest algorithms in browser-oriented JavaScript |