This file provides guidance to Claude Code (claude.ai/code) when working with this repository.
pnpm workspaces monorepo. Publishable packages live under packages/* (@nestjs-redis/*). Example app: examples/full (optional, not critical CI).
# All publishable packages
pnpm build
pnpm typecheck
pnpm test
pnpm lint # oxlint (root .oxlintrc.json)
pnpm format:check # oxfmt --check
pnpm format # oxfmt
# Single package
pnpm --filter @nestjs-redis/client build
pnpm --filter @nestjs-redis/lock test
pnpm --filter @nestjs-redis/throttler-storage lint
pnpm --filter @nestjs-redis/client typecheck
# Single test file
pnpm --filter @nestjs-redis/client test -- path/to/file.spec.ts
# Release (lockstep packages/*/ version, tag vX.Y.Z, push → CI: npm + draft GH Release)
pnpm release # interactive; or: pnpm release patch|minor|major|1.4.0Start Redis before running any tests: docker compose up redis -d
(Cluster suites also need docker compose up redis-cluster -d.)
Independently installable NestJS packages under packages/, all @nestjs-redis/* scoped:
| Package | Purpose |
|---|---|
client |
Core. DI-managed Redis connections (Client/Cluster/Sentinel). All other packages depend on this. |
health-indicator |
Terminus health check integration. |
lock |
Distributed locking via @redis-kit/lock (RedlockModule, RedlockService, @Redlock() decorator). |
schedule |
Distributed cron execution, drop-in for @nestjs/schedule. |
socket.io-adapter |
Redis adapter for Socket.IO horizontal scaling. |
streams-transporter |
Redis Streams microservices transport with consumer groups. |
throttler-storage |
ThrottlerStorage impl using Lua scripting for atomic rate limiting. |
All packages use ConfigurableModuleBuilder from @nestjs/common:
// module-definition.ts sets .setClassMethodName('forRoot') and factory name
export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } =
new ConfigurableModuleBuilder<RedisModuleOptions>({
moduleName: 'RedisClient',
})
.setClassMethodName('forRoot')
.setFactoryMethodName('createRedisOptions' as keyof RedisOptionsFactory)
.build();The client module exports tokens via RedisToken(connectionName?):
- No name → token
'REDIS_CLIENT' - Named
'cache'→ token'REDIS_CLIENT_CACHE'(uppercased)
Use @InjectRedis(connectionName?) or Inject(RedisToken(connectionName?)) to inject clients.
RedisModuleOptions = connection config only (type, options). RedisModuleForRootOptions adds isGlobal and connectionName. The useFactory in forRootAsync returns RedisModuleOptions — not RedisModuleForRootOptions.
- Tests:
*.spec.ts— Redis must be running for tests that need a live instance - Runner: Vitest with SWC (
unplugin-swc) for decorator metadata - Package script:
test(vitest run) - Start Redis:
docker compose up redis -d
- redis package: node-redis v5+ (
redis ^5.0.0 || ^6.0.0), not ioredis. Types:RedisClientType,RedisClusterType,RedisSentinelType. - TypeScript: strict mode,
target: ES2022,module: nodenext,moduleResolution: nodenext,customConditions: ["development"],noUnusedLocals,noImplicitReturns. - No barrel re-exports inside lib/:
index.tsatsrc/level only. Internal imports use direct paths. - Client lifecycle:
RedisModuleconnects on startup, disconnects ononApplicationShutdown. Other services (e.g.,RedisThrottlerStorage) do not manage their client's lifecycle. - Lua scripts in
throttler-storage: loaded lazily, SHA cached, NOSCRIPT fallback re-runs with raw script. - Conventional commits required. Releases:
pnpm release(release-it tag/push) then publish CI (npm + draft GitHub Release; publish the draft after review). - Debug logging: gated on
process.env['REDIS_MODULE_DEBUG'] === 'true'; errors always log.
-
Using ioredis types: This repo uses
redis(node-redis), not ioredis. Do not useIORedis,Redisfrom ioredis, or ioredis-style APIs. -
RedisModuleOptionsvsRedisModuleForRootOptions:useFactoryinforRootAsyncmust returnRedisModuleOptions(connection config only — noisGlobal/connectionName). Those fields are onRedisModuleForRootOptionsandRedisModuleAsyncOptionsonly. -
Token format:
RedisToken('cache')produces'REDIS_CLIENT_CACHE'(uppercased). Do not construct token strings manually. -
RedlockServiceis justclass RedlockService extends Redlock {}: It directly extendsRedlockfrom@redis-kit/lockfor DI injection. No wrapper logic — useRedlockAPI directly on the injected service. -
No
RedisServiceclass: There is no service class in theclientpackage. Connections are injected directly via@InjectRedis(). Do not create or reference aRedisService. -
throttler-storageconstructor takes a pre-existing client:new RedisThrottlerStorage(client)— the service does NOT manage the client lifecycle or create its own connection. -
moduleResolution: nodenext: Relative imports in TypeScript source files must include.jsextension. Do not use extensionless relative imports in new files. -
ConfigurableModuleBuilderfactory method name: The factory interface method iscreateRedisOptions(set viasetFactoryMethodName), not the builder defaultcreate. Implement this inRedisOptionsFactory. -
forRoot/forRootAsyncreturn an anonymous subclass: Themodulefield isclass extends RedisModule { override connectionName = ... }. The module class is notRedisModuleitself; do not reference it by name in that context.
Before submitting changes to any package:
-
pnpm --filter @nestjs-redis/<package> lintpasses -
pnpm --filter @nestjs-redis/<package> typecheckpasses -
pnpm --filter @nestjs-redis/<package> testpasses (Redis must be running) - Public API changes reflected in
packages/<pkg>/src/index.ts - Commit message follows conventional commit format (
feat:,fix:,chore:, etc.)
| File | Purpose |
|---|---|
packages/client/src/lib/module.ts |
Core module; forRoot/forRootAsync/shutdown pattern |
packages/client/src/lib/tokens.ts |
RedisToken() token factory |
packages/client/src/lib/types.ts |
RedisModuleOptions, RedisModuleForRootOptions, RedisConnectionConfig |
packages/client/src/lib/redis-client.module-definition.ts |
ConfigurableModuleBuilder setup |
packages/client/src/lib/interfaces/ |
Async options and factory interfaces |
packages/throttler-storage/src/lib/throttler-storage.service.ts |
Lua script pattern, evalSha + NOSCRIPT fallback |
packages/lock/src/lib/redlock/ |
Redlock module/service/decorator |
tsconfig.base.json |
Shared TS compiler options |