fast-deep-equal-rs
v0.1.2
Published
Ultra-fast object hashing for memoization and caching - powered by Rust's ahash algorithm
Maintainers
Readme
fast-object-hash-rs
Ultra-fast object hashing for memoization and caching - powered by Rust
A high-performance JavaScript object hashing library that leverages Rust's ahash algorithm to provide 1.37x faster hashing than pure JavaScript for large objects (1000 keys).
Why This Library?
Deep equality checking in JavaScript is fast enough for most use cases, but object hashing for caching benefits from Rust's performance on large datasets:
- ✅ Hash large objects (1000 keys) 1.37x faster than JavaScript
- ✅ 61.6% less memory usage for very large objects (10,000+ keys)
- ✅ Optimized versions (
fastHashOptimized) avoid FFI overhead - ✅ Perfect for memoization and caching use cases
- ✅ Multiple hash functions for different needs
- ✅ Built-in memoization helpers
- ⚠️ JavaScript is faster for small objects (< 100 keys) due to FFI overhead
Installation
npm install fast-object-hash-rsQuick Start
const { fastHash, createMemo, createCache } = require('fast-object-hash-rs');
// Simple hashing
const hash = fastHash({ user: 'john', age: 30 });
console.log(hash); // "a3f5c21b8d4e"
// Memoization
const expensiveFn = createMemo((data) => {
// expensive computation
return processData(data);
});
// Will only compute once for same input
const result1 = expensiveFn(largeObject);
const result2 = expensiveFn(largeObject); // ← Cached!
// Object-based caching
const cache = createCache();
cache.set(complexObject, computedValue);
const value = cache.get(complexObject); // Fast lookup by contentAPI
fastHash(obj: any): string
Ultra-fast hashing using Rust's ahash algorithm. Returns a hex string suitable for use as a Map key.
const hash = fastHash({ a: 1, b: 2, c: 3 });Best for: General-purpose caching, memoization
fastHashNumber(obj: any): number
Even faster - returns a numeric hash. Use when you don't need string keys.
const hash = fastHashNumber(largeObject);Best for: When you need maximum speed and can use numeric keys
stableHash(obj: any): string
Sorted-key hash that guarantees the same hash for {a:1,b:2} and {b:2,a:1}.
stableHash({ a: 1, b: 2 }) === stableHash({ b: 2, a: 1 }); // trueBest for: When object key order varies but content is the same
hashEquals(a: any, b: any): boolean
Fast equality check using hash comparison. Faster than deep equality for large objects.
if (hashEquals(largeObj1, largeObj2)) {
// Objects are equal
}Best for: Comparing very large objects (1000+ keys)
fastHashBatch(objects: any[]): string[]
Hash multiple objects at once - amortizes FFI overhead for 2-3x speedup.
const hashes = fastHashBatch([obj1, obj2, obj3, obj4]);Best for: Hashing many objects in bulk
secureHash(obj: any): string
Cryptographic SHA-256 hash. Slower but collision-resistant.
const hash = secureHash(sensitiveData);Best for: When you need guaranteed uniqueness
createMemo(fn): function
Create a memoized version of a function that caches results based on argument hashing.
const memoized = createMemo((a, b, c) => {
// expensive operation
return a + b + c;
});
memoized(1, 2, 3); // Computed
memoized(1, 2, 3); // Cached!createCache(): Cache
Create a cache that uses object content for lookups (not reference equality).
const cache = createCache();
cache.set({ user: 'john' }, userData);
cache.get({ user: 'john' }); // ← Works! Same content = same hash
cache.has(obj);
cache.delete(obj);
cache.clear();Performance Benchmarks
Results on M1 MacBook Pro:
Small Objects (3 keys)
Rust fastHash: 1,932,950 ops/sec
Rust fastHashNumber: 2,150,706 ops/sec
JavaScript hash: 6,182,923 ops/sec
Result: JavaScript 3.2x faster (FFI overhead dominates)Medium Objects (50 keys)
Rust fastHash: 439,824 ops/sec
Rust fastHashNumber: 448,724 ops/sec
JavaScript hash: 504,248 ops/sec
Result: JavaScript 1.15x fasterLarge Objects (1000 keys)
Rust fastHash: 7,297 ops/sec (1.34x faster)
Rust fastHashNumber: 7,305 ops/sec (1.34x faster)
Rust fastHashOptimized: 7,486 ops/sec (1.37x faster) ⭐
Rust fastHashNumberOptimized: 7,472 ops/sec (1.37x faster) ⭐
JavaScript hash: 5,460 ops/sec
Speedup: Up to 1.37x ✓✓ ← Rust shines here!Nested Object (deep structure)
Rust fastHash: 367,931 ops/sec
Rust fastHashNumber: 374,168 ops/sec
JavaScript hash: 407,420 ops/sec
Result: JavaScript 1.1x fasterCryptographic Hashing (SHA-256)
Rust SHA-256: 252,634 ops/sec
Node.js crypto: 456,156 ops/sec
Result: Node.js crypto 1.8x faster💡 Key Insight: Rust delivers 1.37x speedup for large objects (1000 keys). For smaller objects, JavaScript's optimized V8 engine is faster due to FFI overhead.
Run benchmarks yourself:
npm run bench
npm run bench:memoryMemory Usage
Memory consumption comparison (lower is better):
Very Large Objects (10,000 keys)
JavaScript hash: 0.003 KB per operation
Rust fastHashOptimized: 0.001 KB per operation
Memory savings: 61.6% ✓✓✓Summary
- Small objects: Rust uses similar memory to JavaScript
- Medium objects: Rust uses slightly less memory
- Large objects (1000 keys): JavaScript uses ~50% less memory
- Very large objects (10,000+ keys): Rust saves 61.6% memory ⭐
The memory advantage appears at very large object sizes where Rust's efficient string handling outweighs JavaScript's GC optimizations.
Use Cases
✅ Perfect For:
- Memoization - Cache expensive function results
- Request caching - Cache API responses by request parameters
- React/Vue rendering - Fast prop change detection
- Data deduplication - Find duplicate objects in large datasets
- Cache keys - Generate stable cache keys from objects
❌ Not Ideal For:
- Equality checking - Use regular
===orfast-deep-equal - Small objects - V8 is already fast enough
- Frequent small hashes - FFI overhead dominates
Why Not Deep Equality?
We initially built this as a deep equality checker, but discovered that V8 is faster than Rust for traversing objects due to FFI overhead.
However, hashing is perfect for Rust because:
- We only cross the FFI boundary once
- Rust's ahash algorithm is genuinely faster than JS
- The use case (caching) benefits from Rust's speed
See LEARNINGS.md for the full story.
How It Works
JavaScript Object → JSON.stringify (V8 optimized)
→ Cross FFI once
→ ahash in Rust (fast!)
→ Return hash stringThe key optimization: We let V8 handle serialization (what it's good at), then do hashing in Rust (where we're faster).
Requirements
- Node.js >= 10
- Automatically downloads pre-built binaries for:
- macOS (x64, ARM64)
- Linux (x64, ARM64)
- Windows (x64)
Building from Source
# Install Rust toolchain
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Build
npm install
npm run build
# Test
npm test
# Benchmark
npm run benchLicense
MIT
Contributing
Contributions welcome! This project demonstrates:
- Building high-performance Node.js natives modules with Rust
- When to use Rust vs JavaScript
- Optimizing FFI boundaries
- Real-world Rust + napi-rs patterns
Acknowledgments
- Powered by napi-rs
- Uses ahash - the fastest non-cryptographic hash in Rust
- Inspired by object-hash
