@httpx/xcache
v0.5.0
Published
Memory cache for node and browsers
Readme
@httpx/xcache
In memory cache utility
Install
$ npm install @httpx/xcache
$ yarn add @httpx/xcache
$ pnpm add @httpx/xcacheFeatures
- 📐 Lightweight (starts at ~800B)
- 🛡️ Tested on node 20-24, bun, browser, cloudflare workers and runtime/edge.
- 🗝️ Available in ESM and CJS formats.
Documentation
Simple usage
import { XMemCache, TimeLruCache } from "@httpx/xcache";
const xMemCache = new XMemCache({
lru: new TimeLruCache({ maxSize: 50, defaultTTL: 60_000 }),
namespace: "default",
});
const fetchSmth = async (params: { id: number }) => {
return { id: params.id, data: `Data for ${params.id}` };
};
const params = { id: 1 };
const { data } = await xMemCache.runAsync({
key: ["/api/data", params],
fn: () => fetchSmth(params),
});
// data: { id: 1, data: 'Data for 1' }With compression
You can use compression to reduce the size of the cached data. The library supports gzip compression algorithm
To be able to serialize and deserialize the data, you can use adapters like DevalueSerializer,
SuperjsonSerializer or JsonSerializer.
import {
XMemCache,
TimeLruCache,
CacheCompress,
SuperjsonSerializer,
} from "@httpx/xcache";
const xMemCache = new XMemCache({
lru: new TimeLruCache({ maxSize: 50, defaultTTL: 120_000 }),
compressor: new CacheCompress({
// To enable compression the data needs to be serialized
// Choose between SuperJsonSerializer, DevalueSerializer, JsonSerializer
serializer: new SuperjsonSerializer(),
algorithm: "gzip", // or 'deflate'
// Skip compression if the achieved compression ratio is less than
// the provided ratio. 1.3 means that the compression will be skipped
// if the ratio does not give at least 30% memory reduction
// @default 1.3
minimumRatio: 1.3,
// Skip compression if the result is a string shorter than 1000 characters
// @default 1000
minimumStringLength: 1000,
// Skip compression if the achieved byte saving is less than 16 KB
// @default 16_384
minimumByteSaving: 16_384,
}),
});
const fetchThings = async (params: { name: string }) => {
return {
message: `Hello ${params.name}`,
bigint: BigInt("1234567890123456789012345678901234567890"),
date: new Date(),
};
};
// Params will be hashed through @httpx/stable-hash
const params = { name: "cool", createdAt: new Date() };
const { data } = await xMemCache.runAsync({
key: ["/api/data", params],
fn: () => fetchThings(params),
});Benchmarks
Performance is continuously monitored thanks to codspeed.io.
RUN v4.1.0 /home/sebastien/github/httpx/packages/xcache
✓ bench/x-mem-cache.bench.ts > XMemCache benchmarks with 46.7 MB 64878ms
name hz min max mean p75 p99 p995 p999 rme samples
· original function 2.4955 400.41 401.00 400.73 400.89 401.00 401.00 401.00 ±0.03% 10
· with cache (just lru) 5,291,610.29 0.0001 6.1445 0.0002 0.0002 0.0004 0.0007 0.0031 ±2.15% 4233289
· with cache 513,034.43 0.0013 2.8092 0.0019 0.0020 0.0055 0.0085 0.0366 ±1.24% 410428
· cache with json + gzip 0.8131 1,161.82 1,382.36 1,229.84 1,253.09 1,382.36 1,382.36 1,382.36 ±3.54% 10
· cache with superjson + gzip 0.8313 1,128.63 1,376.68 1,202.91 1,222.47 1,376.68 1,376.68 1,376.68 ±4.08% 10
· cache with devalue + gzip 0.4417 2,142.59 2,467.50 2,264.21 2,375.01 2,467.50 2,467.50 2,467.50 ±3.48% 10
✓ bench/serializer.bench.ts > Serializer benchmarks with json 1924ms
name hz min max mean p75 p99 p995 p999 rme samples
· json.serialize(4.52 MB) - native types 34.7313 18.3491 114.08 28.7925 30.9104 114.08 114.08 114.08 ±28.57% 28
· json.deserialize(4.52 MB) - native types 61.1447 14.0582 25.3669 16.3547 17.5522 25.3669 25.3669 25.3669 ±3.67% 49
✓ bench/serializer.bench.ts > Serializer benchmarks with devalue 3548ms
name hz min max mean p75 p99 p995 p999 rme samples
· devalue.serialize(5.66 MB) - native types 5.1668 176.95 244.94 193.54 193.85 244.94 244.94 244.94 ±7.04% 10
· devalue.deserialize(5.66 MB) - native types 28.5541 29.7521 50.5638 35.0213 39.9162 50.5638 50.5638 50.5638 ±7.47% 23
✓ bench/serializer.bench.ts > Serializer benchmarks with superjson 3521ms
name hz min max mean p75 p99 p995 p999 rme samples
· superjson.serialize(4.52 MB) - native types 5.0457 155.96 258.63 198.19 207.44 258.63 258.63 258.63 ±12.33% 10
· superjson.deserialize(4.52 MB) - native types 64.9085 14.0191 20.0136 15.4063 15.4649 20.0136 20.0136 20.0136 ±2.51% 52
✓ bench/serializer.bench.ts > Serializer benchmarks with devalue 7846ms
name hz min max mean p75 p99 p995 p999 rme samples
· devalue.serialize(11.6 MB) - extended types 2.0381 419.75 569.72 490.66 551.97 569.72 569.72 569.72 ±8.16% 10
· devalue.deserialize(11.6 MB) - extended types 8.6823 77.6905 197.99 115.18 124.29 197.99 197.99 197.99 ±20.73% 10
✓ bench/serializer.bench.ts > Serializer benchmarks with superjson 24993ms
name hz min max mean p75 p99 p995 p999 rme samples
· superjson.serialize(16.8 MB) - extended types 0.7203 1,165.80 2,116.25 1,388.25 1,382.20 2,116.25 2,116.25 2,116.25 ±13.84% 10
· superjson.deserialize(16.8 MB) - extended types 1.7432 476.36 742.18 573.66 599.53 742.18 742.18 742.18 ±11.37% 10
✓ bench/cache-key.bench.ts > genCacheKey benches 1020ms
name hz min max mean p75 p99 p995 p999 rme samples
· original function 250,201.57 0.0031 1.0082 0.0040 0.0035 0.0122 0.0215 0.0540 ±0.78% 200162
BENCH Summary
original function - bench/cache-key.bench.ts > genCacheKey benches
json.deserialize(4.52 MB) - native types - bench/serializer.bench.ts > Serializer benchmarks with json
1.76x faster than json.serialize(4.52 MB) - native types
devalue.deserialize(5.66 MB) - native types - bench/serializer.bench.ts > Serializer benchmarks with devalue
5.53x faster than devalue.serialize(5.66 MB) - native types
superjson.deserialize(4.52 MB) - native types - bench/serializer.bench.ts > Serializer benchmarks with superjson
12.86x faster than superjson.serialize(4.52 MB) - native types
devalue.deserialize(11.6 MB) - extended types - bench/serializer.bench.ts > Serializer benchmarks with devalue
4.26x faster than devalue.serialize(11.6 MB) - extended types
superjson.deserialize(16.8 MB) - extended types - bench/serializer.bench.ts > Serializer benchmarks with superjson
2.42x faster than superjson.serialize(16.8 MB) - extended types
with cache (just lru) - bench/x-mem-cache.bench.ts > XMemCache benchmarks with 46.7 MB
10.31x faster than with cache
2120485.35x faster than original function
6365308.96x faster than cache with superjson + gzip
6507834.98x faster than cache with json + gzip
11981322.35x faster than cache with devalue + gzip
See benchmark file for details.
Bundle size
Bundle size is tracked by a size-limit configuration
| Scenario (esm) | Size (compressed) |
| ------------------------------------------ | ----------------: |
| import { XMemCache } from '@httpx/xcache | ~ 800B |
For CJS usage (not recommended) track the size on bundlephobia.
Compatibility
| Level | CI | Description | | ------------ | --- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Node | ✅ | CI for 20.x, 22.x, 24.x & 25.x. | | Browser | ✅ | Tested with latest chrome (vitest/playwright) | | Browserslist | ✅ | > 95% on 01/2025. defaults, chrome >= 96, firefox >= 105, edge >= 113, safari >= 15, ios >= 15, opera >= 103, not dead | | Bun | ✅ | Tested with latest (at time of writing >= 1.3.3) | | Edge | ✅ | Ensured on CI with @vercel/edge-runtime. | | Cloudflare | ✅ | Ensured with @cloudflare/vitest-pool-workers (see wrangler.toml | | Typescript | ✅ | TS 5.0 + / are-the-type-wrong checks on CI. | | ES2022 | ✅ | Dist files checked with es-check | | Performance | ✅ | Monitored with codspeed.io |
For older browsers: most frontend frameworks can transpile the library (ie: nextjs...)
Contributors
Contributions are welcome. Have a look to the CONTRIBUTING document.
Sponsors
If my OSS work brightens your day, let's take it to new heights together! Sponsor, coffee, or star – any gesture of support fuels my passion to improve. Thanks for being awesome! 🙏❤️
Special thanks to
License
MIT © Sébastien Vanvelthem and contributors.
