<!-- PkgPulse AI-readable guide source -->
<!-- Canonical: https://www.pkgpulse.com/guides/ohash-vs-object-hash-vs-hash-wasm-object-hashing-2026 -->
<!-- Raw Markdown: https://www.pkgpulse.com/guides/ohash-vs-object-hash-vs-hash-wasm-object-hashing-2026/raw.md -->
<!-- Source path: content/guides/ohash-vs-object-hash-vs-hash-wasm-object-hashing-2026.mdx -->

---
og_image: "/images/guides/ohash-vs-object-hash-vs-hash-wasm-object-hashing-2026.webp"
title: "ohash vs object-hash vs hash-wasm 2026"
description: "Compare ohash, object-hash, and hash-wasm for hashing objects and data in JavaScript. Deterministic hashing, SHA-256, content addressing, cache keys, and."
date: "2026-03-09"
author: "PkgPulse Team"
tags: ["javascript", "typescript", "developer-tools", "nodejs"]
---

## TL;DR

**ohash** is the UnJS super-fast object hashing library — deterministic hash of any JavaScript value, tiny, zero dependencies, used for cache keys and content addressing. **object-hash** is the mature object hashing library — SHA-1/SHA-256/MD5 of JavaScript objects, handles circular references, configurable key ordering. **hash-wasm** is a WebAssembly-based hashing library — blazing fast SHA-256, MD5, xxHash, Blake3 on raw data (strings/buffers), not specific to objects. In 2026: ohash for hashing JS objects (cache keys, ETags), object-hash for configurable object hashing, hash-wasm for raw data hashing at maximum speed.

## Key Takeaways

- **ohash**: ~10M weekly downloads — UnJS, fast object hashing, deterministic, tiny
- **object-hash**: ~10M weekly downloads — configurable, multiple algorithms, circular reference support
- **hash-wasm**: ~3M weekly downloads — WASM-based, 30+ algorithms, raw data hashing
- ohash produces a quick hash for cache invalidation — not cryptographic
- object-hash produces SHA-1/SHA-256 — deterministic and verifiable
- hash-wasm is for raw data — hashing strings, buffers, files (not JS objects)

---

## Common Use Cases

```
Why hash JavaScript objects?
  ✅ Cache keys — hash(requestParams) → unique cache key
  ✅ ETags — hash(responseBody) → HTTP ETag header
  ✅ Change detection — hash(config) changed? → reload
  ✅ Deduplication — hash(record) → check if already processed
  ✅ Content addressing — hash(data) → deterministic filename

Why hash raw data?
  ✅ File integrity — SHA-256(file) → verify downloads
  ✅ Password hashing — (use bcrypt/argon2 instead)
  ✅ Checksums — MD5(payload) → quick integrity check
  ✅ Bloom filters — xxHash(key) → fast probabilistic lookup
```

---

## ohash

[ohash](https://github.com/unjs/ohash) — fast object hashing:

### Basic usage

```typescript
import { hash, objectHash, murmurHash, sha256 } from "ohash"

// hash() — quick hash of any value:
hash({ name: "react", version: "19.0.0" })
// → "aBcDeFgH" (short, deterministic hash string)

hash([1, 2, 3])
// → "xYzAbCdE"

hash("hello world")
// → "qRsTuVwX"

// Same input → same output (deterministic):
hash({ a: 1, b: 2 }) === hash({ b: 2, a: 1 })
// → true (key order doesn't matter)
```

### Object hashing for cache keys

```typescript
import { hash } from "ohash"

// API response caching:
function getCacheKey(endpoint: string, params: Record<string, unknown>) {
  return hash({ endpoint, params })
}

const key = getCacheKey("/api/packages", { sort: "downloads", limit: 10 })
// → deterministic cache key

// ETag generation:
function generateETag(data: unknown) {
  return `"${hash(data)}"`
}

app.get("/api/packages", (req, res) => {
  const packages = getPackages()
  const etag = generateETag(packages)

  if (req.headers["if-none-match"] === etag) {
    return res.status(304).end()  // Not modified
  }

  res.setHeader("ETag", etag)
  res.json(packages)
})
```

### SHA-256 and Murmur hash

```typescript
import { sha256, murmurHash } from "ohash"

// SHA-256 (cryptographic):
sha256("hello world")
// → "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"

// Murmur hash (fast, non-cryptographic):
murmurHash("hello world")
// → 1586663183

// sha256 for content integrity:
const contentHash = sha256(JSON.stringify(config))
```

### Diff and comparison

```typescript
import { hash, diff } from "ohash"

// diff() — find differences between objects:
const changes = diff(
  { name: "react", version: "18.0.0", downloads: 5_000_000 },
  { name: "react", version: "19.0.0", downloads: 5_500_000 }
)
// → [
//   { type: "changed", key: "version", oldValue: "18.0.0", newValue: "19.0.0" },
//   { type: "changed", key: "downloads", oldValue: 5000000, newValue: 5500000 }
// ]

// isEqual — deep equality check:
import { isEqual } from "ohash"
isEqual({ a: 1 }, { a: 1 }) // → true
```

---

## object-hash

[object-hash](https://github.com/puleos/object-hash) — configurable object hashing:

### Basic usage

```typescript
import objectHash from "object-hash"

// SHA-1 by default:
objectHash({ name: "react", version: "19.0.0" })
// → "a1b2c3d4e5f6..." (40-char SHA-1 hex)

// SHA-256:
objectHash({ name: "react" }, { algorithm: "sha256" })
// → "abcdef123456..." (64-char SHA-256 hex)

// MD5:
objectHash({ name: "react" }, { algorithm: "md5" })
// → "a1b2c3d4..." (32-char MD5 hex)
```

### Configuration options

```typescript
import objectHash from "object-hash"

// Key ordering (default: sorted):
objectHash({ b: 2, a: 1 }) === objectHash({ a: 1, b: 2 })
// → true (keys sorted before hashing)

// Disable key sorting:
objectHash({ b: 2, a: 1 }, { unorderedObjects: false })
// → different from objectHash({ a: 1, b: 2 }, { unorderedObjects: false })

// Exclude specific keys:
objectHash({ name: "react", _internal: "skip" }, {
  excludeKeys: (key) => key.startsWith("_"),
})

// Respect type differences:
objectHash({ value: 1 }, { respectType: true })
// Different from objectHash({ value: "1" })
```

### Circular references

```typescript
import objectHash from "object-hash"

// Handles circular references:
const obj: any = { name: "react" }
obj.self = obj  // Circular!

objectHash(obj)
// → works fine, circular reference detected and handled

// ohash would throw on circular references by default
```

### Specific value hashing

```typescript
import objectHash from "object-hash"

// Hash specific types:
objectHash.sha1({ name: "react" })     // SHA-1
objectHash.MD5({ name: "react" })      // MD5
objectHash.keysMD5({ name: "react" })  // MD5 of keys only

// Write to stream (for large objects):
objectHash.writeToStream({ name: "react" }, { algorithm: "sha256" })
```

---

## hash-wasm

[hash-wasm](https://github.com/nicolo-ribaudo/hash-wasm) — WASM-based hashing:

### Fast hashing

```typescript
import { sha256, md5, xxhash64, blake3 } from "hash-wasm"

// SHA-256:
const hash = await sha256("hello world")
// → "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"

// MD5:
const md5Hash = await md5("hello world")
// → "5eb63bbbe01eeed093cb22bb8f5acdc3"

// xxHash64 (ultra-fast, non-cryptographic):
const xxHash = await xxhash64("hello world")
// → "d4a1185c118f2a57"

// Blake3 (modern, fast cryptographic):
const blake = await blake3("hello world")
// → "d74981efa70a0c880b8d8c1985d075dbcbf679b99a5f9914e5aaf96b831a9e24"
```

### Buffer/file hashing

```typescript
import { sha256, createSHA256 } from "hash-wasm"
import { readFile } from "node:fs/promises"

// Hash a file:
const buffer = await readFile("package.json")
const fileHash = await sha256(buffer)

// Streaming hash (for large files):
const hasher = await createSHA256()
hasher.init()

// Process in chunks:
for await (const chunk of readStream) {
  hasher.update(chunk)
}

const result = hasher.digest("hex")
```

### Performance advantage

```
Benchmark (hashing 1 MB of data):

  hash-wasm (SHA-256, WASM):  ~450 MB/s
  Node.js crypto (SHA-256):    ~400 MB/s
  pure JS sha256:              ~50 MB/s

  hash-wasm (xxHash64, WASM): ~3,000 MB/s
  Node.js crypto (N/A):       —
  pure JS xxhash:             ~200 MB/s

hash-wasm is fastest in browsers (no native crypto).
In Node.js, built-in crypto is comparable for SHA-256.
xxHash/Blake3 via hash-wasm is much faster than any pure JS option.
```

### Available algorithms

```typescript
import {
  md5, sha1, sha256, sha512,       // Standard
  xxhash32, xxhash64, xxhash128,   // xxHash (non-crypto, ultra-fast)
  blake2b, blake2s, blake3,         // Blake (modern crypto)
  crc32, adler32,                   // Checksums
  argon2id, bcrypt, scrypt,         // Password hashing
  sha3_256, sha3_512,               // SHA-3
  keccak256, keccak512,             // Keccak
} from "hash-wasm"

// 30+ algorithms available — all WASM-accelerated
```

---

## Feature Comparison

| Feature | ohash | object-hash | hash-wasm |
|---------|-------|------------|----------|
| Hash JS objects | ✅ | ✅ | ❌ (raw data) |
| Hash raw data | ✅ (sha256) | ❌ | ✅ |
| Deterministic | ✅ | ✅ | ✅ |
| Key order independent | ✅ | ✅ (configurable) | N/A |
| Circular references | ❌ | ✅ | N/A |
| Algorithm choice | murmur, SHA-256 | SHA-1, SHA-256, MD5 | 30+ algorithms |
| WASM accelerated | ❌ | ❌ | ✅ |
| Streaming | ❌ | ✅ | ✅ |
| Object diff | ✅ | ❌ | ❌ |
| Browser support | ✅ | ✅ | ✅ |
| Dependencies | 0 | 0 | 0 |
| Weekly downloads | ~10M | ~10M | ~3M |

---

## When to Use Each

**Use ohash if:**
- Need fast cache keys from JavaScript objects
- Building ETags or content-addressed storage
- In the UnJS ecosystem (Nuxt, Nitro, H3)
- Want object diff and equality utilities alongside hashing

**Use object-hash if:**
- Need configurable hashing (algorithm, key ordering, exclusions)
- Objects may have circular references
- Want SHA-1/SHA-256/MD5 hashes of JavaScript objects
- Need streaming hash support for large objects

**Use hash-wasm if:**
- Hashing raw data (strings, buffers, files) not JS objects
- Need maximum performance (WASM-accelerated)
- Want exotic algorithms (xxHash, Blake3, Keccak)
- Building file integrity checks, checksums, or content addressing

---

## Handling Undefined, Functions, and Special JavaScript Values

A practical consideration when hashing JavaScript objects is how each library handles values that don't serialize cleanly to JSON. `undefined`, functions, `Symbol`, circular references, `Date`, `Map`, `Set`, `RegExp`, and class instances all have subtly different behavior across the three libraries, and incorrect assumptions lead to bugs where two different objects hash to the same value (or fail with an error).

ohash serializes objects by converting them to a canonical string representation. `undefined` values are omitted from serialized object properties (consistent with `JSON.stringify`), so `{ a: 1, b: undefined }` hashes identically to `{ a: 1 }`. Functions are serialized using their source code text, meaning two functions with identical implementations but different names produce different hashes. Dates are serialized as their ISO string representation. ohash does not handle circular references by default and will enter an infinite loop — use `serializeCircular: true` option to enable safe circular reference handling.

object-hash is the most comprehensive in handling edge cases. It serializes `Date` as the numeric timestamp, `RegExp` as its source and flags, `Function` as its source code, `Set` and `Map` as sorted arrays of their entries, and circular references by tracking previously-seen objects and inserting a back-reference marker. This makes object-hash the safest choice when hashing arbitrary runtime objects whose structure you don't fully control — configuration objects that may contain non-JSON-serializable values, API response objects that may include unexpected types, or third-party library objects.

hash-wasm operates on raw bytes and cannot hash JavaScript objects directly — you must serialize them first (typically with `JSON.stringify`) and pass the resulting string or buffer. This means you must handle special values yourself before hashing. For the raw-data hashing use cases that hash-wasm targets (file buffers, binary protocol data), this is not a limitation since the input is already a `Buffer` or `Uint8Array`.

## Migration Guide

### From object-hash to ohash for cache keys

The most common use case is generating stable cache keys from JavaScript objects. ohash is faster and zero-dependency, making it the better default for this pattern:

```typescript
// object-hash (old)
import objectHash from "object-hash"
const cacheKey = objectHash({ userId: "123", filters: { status: "active", page: 1 } })
// → "a3f9b0..." (SHA-1 by default)

// ohash (new)
import { hash } from "ohash"
const cacheKey = hash({ userId: "123", filters: { status: "active", page: 1 } })
// → "v38sm2..." (murmur hash, faster, deterministic)

// ohash's hash is designed for cache keys, not security:
// - Don't use ohash for password hashing or content verification signatures
// - Use hash-wasm or Node.js crypto for security-sensitive hashing
```

ohash handles key ordering, circular reference detection for common cases, and type coercion consistently. The output format differs from object-hash but is equally deterministic.

## Community Adoption in 2026

**ohash** and **object-hash** each reach approximately 10 million weekly downloads — a statistical coincidence that reflects very different adoption stories. ohash's downloads are dominated by transitive dependencies through the UnJS ecosystem (Nitro, H3, Nuxt's caching internals). Direct intentional use of ohash is lower; most consumers have it installed because Nuxt or a Nuxt-compatible tool pulled it in. object-hash's downloads represent direct use in caching middleware, ETagger libraries, and content-addressed storage implementations where teams explicitly chose it for its configurable algorithm support.

**hash-wasm** reaches approximately 3 million weekly downloads, used primarily in browser-based applications where native crypto access is limited and pure-JavaScript hashing is too slow. In Node.js environments, hash-wasm competes directly with the built-in `crypto` module — and loses on convenience while winning on breadth of algorithms (xxHash64, Blake3, Keccak are not available in Node.js crypto). For teams that need non-standard hash algorithms, hash-wasm is the most complete option available as an npm package.


## Hash Collision Probability and Use Case Fit

Understanding the statistical properties of each hash function is essential for choosing the right tool and determining whether a collision would cause a correctness bug or just a cache miss.

**Hash collision probability** is a function of hash output size and the number of items being hashed. ohash produces a 64-character hexadecimal string (256-bit output from SHA-256 internally), giving a collision probability of approximately 1 in 2^128 for any two random inputs — astronomically low for all practical purposes. object-hash uses Node.js's `crypto.createHash()` with configurable algorithms; the default SHA1 (160-bit) has known theoretical weaknesses but is still collision-resistant for non-adversarial caching use cases. hash-wasm exposes the full algorithm selection including SHA-3 variants and BLAKE2, with hash sizes up to 512 bits for maximum collision resistance.

**Adversarial resistance** matters when hashes are used for security-sensitive purposes. Cache invalidation, content-addressable storage for developer tools, and change detection are non-adversarial: an attacker cannot influence the content being hashed. API request signing, file integrity verification, and password hashing are adversarial: a determined attacker may craft inputs designed to produce specific hash outputs. For adversarial use cases, cryptographic hash functions (SHA-256 or SHA-3, as provided by hash-wasm) are required; ohash and object-hash's fast non-cryptographic modes are explicitly inappropriate.

**Determinism across environments** is critical for distributed cache keys. ohash serializes JavaScript objects deterministically — `{ b: 2, a: 1 }` and `{ a: 1, b: 2 }` produce the same hash because ohash sorts object keys before hashing. object-hash similarly sorts keys by default. This determinism ensures that the same object produces the same hash whether computed in a Next.js server in US-East-1 or EU-West-1, making it safe to use ohash as a distributed cache key generator.

For high-performance scenarios where hashing thousands of objects per second matters (module bundlers, reactive frameworks checking for state changes), benchmark the specific object structures you'll hash. ohash's default mode is optimized for JSON-serializable objects and outperforms object-hash significantly for simple objects. hash-wasm's fastest algorithms (xxHash, MurmurHash3) outperform SHA-256 by 5-10x but at the cost of weaker collision resistance — appropriate for hash tables and caching, not for content integrity verification.

## Methodology

Download data from npm registry (weekly average, February 2026). Feature comparison based on ohash v1.x, object-hash v3.x, and hash-wasm v4.x.

*[Compare hashing and cryptography packages on PkgPulse →](https://www.pkgpulse.com)*

*See also: [AVA vs Jest](/compare/ava-vs-jest) and [klona vs rfdc vs structuredClone](/guides/klona-vs-rfdc-vs-structured-clone-deep-copy-javascript-2026), [acorn vs @babel/parser vs espree](/guides/acorn-vs-babel-parser-vs-espree-javascript-ast-parsers-2026).*
