Serialization
Understand encoded values, default compression, and independent L1 and L2 write policies.
Built-in L1 and Redis L2 retain encoded values. This makes payload retention measurable and prevents a later L1 hit from sharing the original mutable object. Encoding and decoding cost CPU, so choose a policy using your payload sizes and latency budget.
Default encoding
Values use MessagePack. Compression is selected from the packed size:
| Packed size | Codec attempted |
|---|---|
| Below 256 bytes | None |
| 256 bytes to below 4 KiB | LZ4 |
| 4 KiB or more | Zstd when available in node:zlib, otherwise LZ4 |
The compressed payload is kept only when it saves at least 15% compared with packed MessagePack. Otherwise the value stays uncompressed. auto selects these same default tiers.
Compression is lossless. Selecting JSON changes value semantics: use JSON-compatible records, because Date, Map, and typed arrays do not retain their JavaScript types through JSON serialization.
Choose codecs per layer
L1 and L2 can use different write policies in 0.5.3. For example, you can avoid compression CPU for L1 writes while retaining the default size tiers for Redis:
import { setupCache } from 'lazy-layers-cache'
export const cache = await setupCache({
namespace: 'catalog-api',
redis: { required: true },
levels: {
L1: { codec: { format: 'msgpack', compression: 'none' } },
L2: { codec: { format: 'msgpack', compression: 'auto' } },
},
})Measure before choosing this override. Uncompressed L1 uses more of the byte budget. Matching L1 and L2 policies let the cache reuse encoded bytes during promotion, while differing policies require re-encoding.
The configuration reference lists formats, compression shorthands, custom tiers, and process-wide defaults.
Read compatibility
Every encoded value identifies its format with a four-byte tag:
| Tag | Stored representation |
|---|---|
HC1M | MessagePack |
HC1L | LZ4-compressed MessagePack |
HC1Z | Zstd-compressed MessagePack |
HC1G | Gzip-compressed MessagePack |
HC1S | Snappy-compressed MessagePack |
HC1J | JSON |
Changing a write policy does not rewrite existing entries. Readers choose the decoder from the tag, independently of their write policy. The LZ4 and Snappy modules ship as dependencies. Zstd support depends on the Node.js runtime.
An unknown tag, unavailable decoder, or corrupt payload decodes to null, which built-in stores treat as a miss. That can increase origin traffic. Before changing a fleet's write codec, verify every reader supports it. See the Redis key-layout migration separately when upgrading the storage layout.
Measure your values
Use a representative application value and an explicit policy when comparing encodings:
import { serializeWithStats } from 'lazy-layers-cache'
const value = { id: '42', name: 'Ada', plan: 'pro' }
const stats = serializeWithStats(value, {
format: 'msgpack',
compression: 'auto',
})
console.log({
encoding: stats.encoding,
originalBytes: stats.originalBytes,
storedBytes: stats.storedBytes,
compressionRatio: stats.compressionRatio,
})storedBytes includes the wire tag. For MessagePack, originalBytes is the packed size and compressionRatio is the fraction saved by compression. These are payload measurements, not total Node.js or Redis memory usage.
Use the benchmark harness for repeatable comparisons on your runtime. Use observability to inspect stored encodings and sizes in a running cache.
Where to next
- Serialization configuration lists the complete write-policy options.
- Environment variables documents process-wide overrides.
- Layers connects encoded size to the L1 budget.