This library seamlessly integrates RedisOM into NestJS, offering:
- Decorator-based Schema Definition: Define your entities using
@Schemaand@Prop. - Repository Injection: Inject repositories directly into your services using
@InjectRepository. - Seamless Connection: Configure your Redis connection globally with
forRootorforRootAsync.
npm install @alpha018/nestjs-redisom redis-om redisUse the @Schema() decorator to define your entity and @Prop() for properties. Extends BaseEntity to easily access the auto-generated ID.
import { Schema } from 'nestjs-redisom';
import { Prop } from 'nestjs-redisom';
import { BaseEntity } from 'nestjs-redisom';
@Schema()
export class CatEntity extends BaseEntity {
@Prop()
name: string;
@Prop()
age: number;
}Note: For all available property decorators, indexing options, and schema definitions, see the Wiki: Defining Structures.
Register RedisOmModule in your root AppModule and register your entities with forFeature.
import { Module } from '@nestjs/common';
import { RedisOmModule } from 'nestjs-redisom';
import { CatEntity } from './cat.entity';
@Module({
imports: [
RedisOmModule.forRoot({
url: 'redis://localhost:6379'
}),
RedisOmModule.forFeature([CatEntity]),
],
})
export class AppModule {}Note: For advanced connection setups, environmental validation, and asynchronous options, see the Wiki: Configuration.
Inject the repository to save and search for entities.
import { Injectable } from '@nestjs/common';
import { InjectRepository } from 'nestjs-redisom';
import { Repository } from 'redis-om';
import { CatEntity } from './cat.entity';
@Injectable()
export class CatsService {
constructor(
@InjectRepository(CatEntity) private readonly catRepo: Repository<CatEntity>,
) {}
async create(name: string, age: number) {
const entity = new CatEntity();
entity.name = name;
entity.age = age;
return await this.catRepo.save(entity);
}
async findAll() {
return await this.catRepo.search().return.all();
}
}Note: To learn about all search capabilities and query building, see the Wiki: Searching.
You can define nested objects using classes and the @Prop({ type: () => Class }) syntax. This allows Redis OM to automatically generate the correct schema fields for your nested data.
How it works:
The library flattens nested properties into the Redis schema using the format parentProperty_childProperty (underscore separator). This allows you to index and search deeply nested fields without complex JSON path syntax.
Define the Embedded Class:
export class Address {
@Prop({ indexed: true })
street: string;
@Prop({ indexed: true })
city: string; // Will become 'address_city' in the schema
}Use in Parent Entity:
@Schema({ dataStructure: 'JSON' })
export class Person extends BaseEntity {
@Prop()
name: string;
@Prop({ type: () => Address })
address: Address;
}Search using flattened/nested fields:
Since the schema uses flattened keys, you query them using the underscore syntax:
// Search for persons where address.city is 'New York'
const results = await this.personRepo.search()
.where('address_city' as any) // Use the flattened key
.eq('New York')
.return.all();Note: Discover more about embedded objects and array structures in the Wiki: Defining Structures.
You can explicitly set the ID when saving an entity if you don't want to use the auto-generated ULID. This is useful for using existing IDs (like UUIDs, emails, or external system IDs).
// Using a UUID
import { v4 as uuidv4 } from 'uuid';
const id = uuidv4();
await this.catRepo.save(id, entity);
// Using a custom string
await this.catRepo.save('unique-custom-id', entity);Note: Read more about identifier strategies in the Wiki: Defining Structures.
You can set an expiration time (in seconds) for an entity. The key will automatically be deleted from Redis after the specified time.
const id = 'temp-session-123';
await this.catRepo.save(id, sessionEntity);
// Expire after 60 seconds
await this.catRepo.expire(id, 60);Note: See entity expiration patterns in the Wiki: Defining Structures.
For secure connections (e.g., AWS ElastiCache, Redis Cloud), use the rediss:// protocol and provide TLS options in the socket configuration.
Static Configuration:
import * as fs from 'fs';
RedisOmModule.forRoot({
url: 'rediss://your-redis-instance:6380',
socket: {
tls: true,
rejectUnauthorized: false, // Set to true if using a public CA
// ca: fs.readFileSync('path/to/ca.pem'), // Optional: Load custom CA
},
})Async Configuration (e.g., using ConfigService):
RedisOmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
url: config.get('REDIS_URL'), // e.g., 'rediss://...'
socket: {
tls: true,
rejectUnauthorized: config.get('REDIS_TLS_REJECT_UNAUTHORIZED') === 'true',
},
}),
})Note: Find more cloud connection examples in the Wiki: Configuration.
nestjs-redisom natively supports connecting to a Redis Cluster using the underlying createCluster functionality of Node-Redis.
Instead of providing a single url, you provide an array of rootNodes:
RedisOmModule.forRoot({
rootNodes: [
{ url: 'redis://redis-cluster-node-1:7000' },
{ url: 'redis://redis-cluster-node-2:7000' }
],
defaults: {
password: 'your-cluster-password'
}
})Note: For full details on how the Node-Redis client uses these initial nodes for cluster auto-discovery (
CLUSTER SLOTS), please refer to the Configuration Wiki.
- Schema Factory: Automatically generates RedisOM schemas from your class metadata.
- Nested Objects: Support for typed nested objects with automatic schema flattening.
- Async Configuration: Supports
useFactory,useClass, anduseExistingfor configuration. - Validation: Compatible with
class-validator(standard NestJS practice).
This library leverages RediSearch (module of Redis Stack), meaning searches are efficient and non-blocking.
When you use @Prop({ indexed: true }), Redis OM creates an Inverted Index.
- Search:
repo.search()...queries this index directly. It does NOT perform a linear scan (SCAN command) over the keyspace. - Complexity: Searches are typically O(K) (where K is the number of results) or O(log N) for range queries. Retrieving by ID is O(1).
| Data Type | Operation | Complexity | Notes |
|---|---|---|---|
| ID | Retrieve (fetch) |
O(1) | Direct key access (fastest). |
| Tag / String | Exact Match (eq) |
O(K) | K = number of results returned. |
| Numeric / Date | Range (gt, lt, between) |
O(log N + K) | Uses sorted sets/trees. efficient for ranges. |
| Text | Full-Text (matches) |
O(M + K) | M = number of terms/words being searched. |
| Geo | Radius / Polygon | O(K + log N) | Geospacial indexing. |
- Memory (RAM): Indexes consume additional memory. Best Practice: Only index fields that you intend to filter by.
- CPU: Search operations are highly optimized. Initial indexing of a large existing dataset may temporarily consume CPU, but incremental updates (
save) are lightweight.
Check out a few resources that may come in handy when working with NestJS:
- Visit the NestJS Documentation to learn more about the framework.
- Visualize your application graph and interact with the NestJS application in real-time using NestJS Devtools.
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please read more here.
- Author - Tomás Alegre
NestJS RedisOM is MIT licensed.