Redis Caching in Twenty CRM: Architecture and Implementation Patterns

Redis serves as the primary in-memory data store for Twenty CRM, powering workspace-level caching, real-time GraphQL subscriptions, shared session storage, and background job processing.

Redis caching is integral to the performance and scalability of Twenty CRM, the open-source customer relationship management platform developed by twentyhq. According to the source code in the packages/twenty-server directory, Redis handles everything from reducing PostgreSQL query load to enabling real-time collaboration across horizontally scaled server instances. This article examines the five critical architectural domains where Twenty CRM leverages Redis to maintain low latency and high availability.

Workspace Caching Strategy

Twenty CRM implements a sophisticated workspace cache to minimize expensive database queries. The WorkspaceCacheService in src/engine/workspace-cache/services/workspace-cache.service.ts manages pre-computed workspace data—including records, metadata, and view state—in a fast key-value map stored in Redis.

When the application requests workspace data, the service first attempts to fetch from Redis. Only on cache misses does it fall back to PostgreSQL, after which it writes the computed data back to Redis for subsequent requests. This pattern significantly reduces database load and keeps the UI responsive even with large workspaces.

// packages/twenty-server/src/engine/workspace-cache/services/workspace-cache.service.ts
const { redisData, missingInRedis } = await this.fetchDataFromRedis(keys);
if (missingInRedis.length) {
  // compute missing data, then write back to Redis
  await this.cacheDataInRedis(missingInRedis);
}
return { ...cachedFromRedis, ...computedMissing };

The CacheStorageService (src/engine/core-modules/cache-storage/services/cache-storage.service.ts) provides a generic wrapper that abstracts whether the underlying store is Redis or an in-memory fallback, ensuring consistent caching semantics across environments.

Real-Time Pub/Sub for GraphQL Subscriptions

Redis enables real-time collaboration through its Pub/Sub capabilities. When one user edits a record, Twenty CRM publishes an event that instantly propagates to all other users viewing the same data via GraphQL subscriptions.

The RedisClientService creates a dedicated Pub/Sub client instance that the SubscriptionsModule consumes. When a record updates, the system publishes a payload to all subscribed clients without polling the database.

// packages/twenty-server/src/engine/subscriptions/subscription.service.ts
const client = this.redisClient.getPubSubClient();   // ← Redis Pub/Sub client
await client.publish('recordUpdated', JSON.stringify(payload));

This architecture ensures that users receive instant notifications about data changes, enabling collaborative features like live cursor tracking and real-time record updates across the Twenty CRM interface.

Session Storage and Authentication

For horizontally scaled deployments, Twenty CRM uses Redis as the session store to guarantee continuity across server instances. The SessionStorageModuleFactory (src/engine/core-modules/session-storage/session-storage.module-factory.ts) configures Express sessions using connect-redis, ensuring that session data persists in Redis rather than local memory.

This implementation allows users to remain authenticated regardless of which server pod handles their request, critical for load-balanced production environments.

// packages/twenty-server/src/engine/core-modules/session-storage/session-storage.module-factory.ts
import RedisStore from 'connect-redis';
import { createClient } from 'redis';

const redisClient = createClient({ url: REDIS_URL });
await redisClient.connect();

@Module({
  providers: [{ provide: 'SESSION_STORE', useFactory: () => new RedisStore({ client: redisClient }) }],
})
export class SessionStorageModule {}

Background Job Processing

Twenty CRM leverages Redis as a lightweight message queue for background workers. The MessageQueueModuleFactory (src/engine/core-modules/message-queue/message-queue.module-factory.ts) uses the same Redis connection—via ioredis—to persist jobs that workers process asynchronously.

This approach handles tasks like email sending and data enrichment without blocking the main application thread. Workers pull jobs from Redis lists using atomic operations, ensuring reliable delivery without requiring a separate message broker like RabbitMQ or Kafka.

// packages/twenty-server/src/engine/core-modules/message-queue/message-queue.module-factory.ts
await redisClientService.getQueueClient().lpush('email:send', JSON.stringify(job));

Health Monitoring and Observability

The platform monitors Redis connectivity through the WorkerHealth indicator (src/engine/core-modules/admin-panel/indicators/worker.health.ts). This health check queries the Redis client to confirm connectivity via redisClient.getQueueClient(), allowing the administrative health endpoint to report Redis status alongside database and other critical services.

Operators gain a single source of truth about system health, ensuring that Redis outages are detected immediately before they impact caching, sessions, or real-time features.

Summary

Redis functions as the backbone of Twenty CRM's distributed architecture by providing:

  • Workspace caching via WorkspaceCacheService to reduce PostgreSQL query load
  • Real-time messaging through Redis Pub/Sub for GraphQL subscription delivery
  • Shared session state using connect-redis for horizontal scalability
  • Reliable job queues through Redis lists processed by background workers
  • Health monitoring integration via the WorkerHealth indicator

By centralizing these concerns in Redis, Twenty CRM achieves low-latency performance and horizontal scalability without deploying separate infrastructure for caching, messaging, and queuing.

Frequently Asked Questions

How does Twenty CRM handle cache invalidation for workspace data?

The WorkspaceCacheService implements a selective invalidation strategy where cache keys are versioned or prefixed by workspace ID. When data mutations occur, the service writes updated values back to Redis immediately, ensuring subsequent reads receive fresh data. For bulk invalidations, the system can flush specific key patterns without clearing the entire Redis instance.

Can Twenty CRM run without Redis?

While the core application can function using in-memory fallbacks provided by CacheStorageService, production deployments require Redis for critical features. Without Redis, real-time GraphQL subscriptions, shared session storage, and distributed background job processing would fail in horizontally scaled environments, limiting the platform to single-instance deployments.

What Redis client libraries does Twenty CRM use?

The codebase utilizes multiple specialized clients: redis (the official Node.js client) for session storage and general caching, ioredis for message queue operations in MessageQueueModuleFactory, and redis Pub/Sub clients for GraphQL subscriptions managed by RedisClientService. This multi-client approach optimizes connection handling for specific use cases.

How does Redis Pub/Sub differ from the message queue implementation?

Pub/Sub (getPubSubClient()) implements a fire-and-forget broadcast pattern where published messages reach all current subscribers instantly, used primarily for real-time GraphQL updates. The message queue (getQueueClient()) utilizes Redis lists with lpush and brpop operations to ensure exactly-once processing by background workers, suitable for reliable task execution like email delivery.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →