Skip to content

Serializers

How data is serialized for storage in Redis (L2 cache).

L2 only

Serialization applies only to L2 (Redis). L1 (memory) stores JavaScript objects directly — no serialization overhead.

Default Behavior

The cache plugin uses JSON serialization internally via the Serializer domain service. This is hardcoded in the plugin — there is no serializer option in CachePlugin config.

typescript
// This is what the plugin registers internally
{ provide: SERIALIZER, useClass: Serializer }  // JSON-only, not configurable

All set(), get(), getOrSet(), and SWR operations use JSON.stringify() / JSON.parse() for L2 storage.

Available Serializers

The package exports serializer classes implementing the ISerializer interface. These are standalone utilities — they can be used independently or as a replacement for the internal serializer via manual provider override.

SerializerOutputTypes SupportedBest For
JsonSerializerstringBasic typesDefault, debugging, general use
MsgpackSerializerBufferBasic + Binary + DateHigh traffic, binary data

ISerializer Interface

typescript
import { type ISerializer } from '@nestjs-redisx/cache';
MethodSignatureDescription
serialize<T>(value: T) => string | BufferConverts value to storage format
deserialize<T>(data: string | Buffer) => TRestores value from storage format. Throws SerializationError on failure.
tryDeserialize<T>(data: string | Buffer) => T | nullSafe version — returns null on error instead of throwing
getContentType() => stringContent type identifier (e.g. 'application/json', 'application/msgpack')

JsonSerializer

typescript
import { JsonSerializer } from '@nestjs-redisx/cache';

const serializer = new JsonSerializer();

const data = { id: 1, name: 'John', active: true };
const serialized = serializer.serialize(data);
// '{"id":1,"name":"John","active":true}'

const deserialized = serializer.deserialize<typeof data>(serialized);
// { id: 1, name: 'John', active: true }

// Safe deserialization (returns null on error)
const invalid = serializer.tryDeserialize('not json');  // null

serializer.getContentType();  // 'application/json'

Pros:

  • Human readable in Redis (redis-cli GET key shows JSON)
  • No extra dependencies
  • Wide compatibility

Cons:

  • Larger payload size
  • Date → ISO string (loses type), Buffer{ type: 'Buffer', data: [...] }

MsgpackSerializer

Uses the msgpackr package (optional dependency, lazy-loaded).

bash
npm install msgpackr
typescript
import { MsgpackSerializer } from '@nestjs-redisx/cache';

const serializer = new MsgpackSerializer();

const data = { id: 1, name: 'John', tags: ['user', 'active'] };
const serialized = serializer.serialize(data);
// Buffer<...> (binary, ~30-40% smaller than JSON)

const deserialized = serializer.deserialize<typeof data>(serialized);
// { id: 1, name: 'John', tags: ['user', 'active'] }

serializer.getContentType();  // 'application/msgpack'

Size comparison utility:

typescript
const comparison = serializer.compareWithJson({ id: 1, name: 'John', tags: ['user'] });
// { jsonSize: 42, msgpackSize: 30, compressionRatio: 1.4 }

Pros:

  • ~30-40% smaller than JSON
  • Handles Date, Buffer natively
  • Faster serialization

Cons:

  • Not human readable in Redis
  • Extra dependency (msgpackr)

msgpackr not installed

If msgpackr is not installed, new MsgpackSerializer() throws immediately:

Error: msgpackr package is required for MsgpackSerializer. Install with: npm install msgpackr

Custom Serializer

Implement all 4 methods of the ISerializer interface:

typescript
import { type ISerializer } from '@nestjs-redisx/cache';

export class CompressedJsonSerializer implements ISerializer {
  serialize<T>(value: T): string {
    return JSON.stringify(value);
  }

  deserialize<T>(data: string | Buffer): T {
    const str = Buffer.isBuffer(data) ? data.toString('utf8') : data;
    return JSON.parse(str) as T;
  }

  tryDeserialize<T>(data: string | Buffer): T | null {
    try {
      return this.deserialize<T>(data);
    } catch {
      return null;
    }
  }

  getContentType(): string {
    return 'application/json+compressed';
  }
}

Using a Custom Serializer with the Plugin

The plugin does not have a serializer config option. To replace the internal serializer, override the SERIALIZER provider manually in your module:

typescript
import { Module } from '@nestjs/common';
import { RedisModule } from '@nestjs-redisx/core';
import {
  CachePlugin,
  MsgpackSerializer,
  SERIALIZER,
} from '@nestjs-redisx/cache';

@Module({
  imports: [
    RedisModule.forRoot({
      clients: { host: 'localhost', port: 6379 },
      plugins: [new CachePlugin()],
    }),
  ],
  providers: [
    // Override the internal serializer
    {
      provide: SERIALIZER,
      useValue: new MsgpackSerializer(),
    },
  ],
})
export class AppModule {}

Type compatibility

The internal Serializer domain service handles string only. JsonSerializer and MsgpackSerializer implement ISerializer which handles string | Buffer. When overriding, ensure the Redis driver can store the output format (Buffer is supported by ioredis).

What Can Be Cached?

TypeJSONMsgPackNotes
Primitives (string, number, boolean)YesYes
nullYesYes
Plain objectsYesYes
ArraysYesYes
DateBecomes ISO stringPreservedJSON requires manual parsing on read
BufferBecomes { type, data }Preserved
Map / SetNo (convert to array first)No (convert to array first)
Class instancesData only (methods lost)Data only (methods lost)Reconstruct manually
Circular referencesThrows SerializationErrorThrows SerializationError

Handling Special Types

Dates

typescript
// JSON — dates become strings
const user = { created: new Date('2025-01-28') };
// Stored: { "created": "2025-01-28T00:00:00.000Z" }
// On read: user.created is a string, not Date

// To restore:
const cached = await cache.get<{ created: string }>('user:1');
const date = new Date(cached.created);

Class Instances

typescript
class User {
  constructor(public id: string, public name: string) {}
  getDisplayName() { return `User: ${this.name}`; }
}

const user = new User('123', 'John');
await cache.set('user:123', user);

const cached = await cache.get<User>('user:123');
// cached.id, cached.name — work fine
// cached.getDisplayName() — TypeError: not a function

// Solution: reconstruct
const restored = Object.assign(new User('', ''), cached);

Best Practices

Use JSON (default) when:

  • Debugging / inspecting cache in Redis is important
  • Data is mostly strings and numbers
  • Payload size is not a concern

Use MsgPack when:

  • High traffic (save bandwidth and Redis memory)
  • Binary data (images, files)
  • Dates must be preserved without manual parsing
  • Every byte matters (large payloads)

Use Custom when:

  • Compression required (very large payloads)
  • Encryption at rest
  • Special encoding (Protocol Buffers, BSON)

Next Steps

Released under the MIT License.