Redis Production Checklist for Django

A production checklist for Redis in Django stacks: separate roles for cache, sessions, and Celery; memory limits and eviction; persistence; network security and TLS; client timeouts; monitoring; and upgrades.

Problem statement

Redis often runs three jobs in a Django deployment at once: the cache, the session store, and the Celery broker and result backend. Each job has different requirements for memory, eviction, and durability, and a single default Redis configuration serves none of them well. Problems appear as users logged out after a restart, tasks silently lost, OOM command not allowed errors, or an unauthenticated Redis port found by an internet scanner.

This checklist reviews Redis for a Django production setup: roles and configuration, memory, persistence, security, client settings, and monitoring. It applies to self-hosted Redis and Valkey and, with minor differences, to managed services.

Redis roles in a Django stackCacheevict freelySessionskeep, boundedCelery brokernever evictResultsexpire quicklyEach role needs its own eviction and persistence rules, ideally on its own instance.
  1. Separate roles: cache on one instance (evicting), broker and sessions on another (not evicting, persistent).
  2. Set maxmemory below available memory on every instance, with the right maxmemory-policy per role.
  3. Enable AOF persistence for the broker and sessions; disable persistence for the cache.
  4. Keep Redis off the public internet; require authentication (ACL users or requirepass) and TLS across untrusted networks.
  5. Configure client timeouts and connection health checks in Django and Celery.
  6. Monitor memory, evictions, connected clients, latency, and queue lengths; alert on thresholds.

Checklist

1. Roles and instances

  • Cache, sessions, and Celery are identified, and each uses a known instance and database number.
  • The cache runs on an instance where eviction is allowed; the broker (and sessions stored only in Redis) run where it is not.
  • Celery results expire (CELERY_RESULT_EXPIRES) or are disabled for tasks whose results are never read.
  • Django settings use separate cache aliases if sessions are cache-backed (SESSION_CACHE_ALIAS).
one Redis role, one policyEvictionPersistenceCacheโœ“allkeys-lrunone neededSessions!noeviction or volatile-lruAOF if logouts matterCelery brokerโœ•noevictionAOF everysecChannels layernoevictionnone neededMixed roles on one instance force the strictest policy on alldjango-deployment.com
Separate instances, or at least separate servers per policy, keep this simple.

2. Memory

  • maxmemory is set on every instance, below the server's or container's memory with headroom for fork-based persistence.
  • Cache instance: maxmemory-policy allkeys-lru (or allkeys-lfu).
  • Broker and session instance: maxmemory-policy noeviction, with alerts before memory fills.
  • Cache entries have timeouts; no unbounded keys from cache.set(..., None) in cache-only instances.
  • Large values are avoided (store IDs or references, not whole rendered pages of megabytes).

3. Persistence and durability

  • Broker and sessions: AOF enabled with appendfsync everysec; data directory on persistent storage or a mounted volume.
  • Cache: save "" and appendonly no.
  • vm.overcommit_memory = 1 on hosts running persistent Redis, so background saves do not fail.
  • A restart test has confirmed that queued tasks and sessions survive (see the persistence guide).

4. Network and access

  • Redis listens only on private interfaces (bind set appropriately) and is not reachable from the internet; firewall or security groups enforce it.
  • protected-mode stays enabled unless authentication and binding are configured deliberately.
  • Authentication is required: ACL users (Redis 6 and newer) with only the needed permissions, or at least requirepass with a long random password.
  • Dangerous commands (FLUSHALL, CONFIG, DEBUG, KEYS) are not available to application users (ACL rules or renamed commands).
  • TLS is enabled when traffic crosses networks you do not fully control (managed services usually offer it; use rediss:// URLs).

5. Client configuration

  • Django cache: socket timeouts are set so a slow or unreachable Redis does not hang requests:
CACHES = {
    "default": {
        "BACKEND": "django.core.cache.backends.redis.RedisCache",
        "LOCATION": os.environ["REDIS_CACHE_URL"],
        "OPTIONS": {
            "socket_connect_timeout": 2,
            "socket_timeout": 2,
            "health_check_interval": 30,
        },
    }
}
timeouts stop Redis hanging requests"BACKEND": "django.core.cache.backends.redis.RedisCache","OPTIONS": {"socket_connect_timeout":2,"socket_timeout":2,"health_check_interval":30,},1231Give up connecting after 2 s instead of hanging a worker.2The same for each command once connected.3Ping idle connections before reusing them.Without timeouts, a Redis outage becomes a site outagedjango-deployment.com
Decide whether cache errors should fail the request or be treated as misses.
  • The application degrades gracefully if the cache is down (pages slower, not failing) where possible; decide per use.
  • Celery broker connection settings include retries on start-up (broker_connection_retry_on_startup) and sensible visibility_timeout for long tasks.
  • Connection counts are bounded: Gunicorn workers, Celery processes, and other clients stay below maxclients.

6. Monitoring

  • Memory used versus maxmemory, and fragmentation ratio.
  • evicted_keys rate (should be near zero for broker and sessions; expected for cache).
  • Cache hit ratio (keyspace_hits versus keyspace_misses).
  • Connected clients, rejected connections, and blocked clients.
  • Latency (redis-cli --latency, or LATENCY monitoring) and slow commands (SLOWLOG GET).
  • Celery queue lengths per queue, and age of the oldest message where tooling allows.
  • Persistence status: aof_last_write_status, rdb_last_bgsave_status.

7. Operations

  • Redis version is supported and receives security fixes; upgrades are planned with a restart window or a replica-based switchover.
  • Configuration lives in version-controlled files or infrastructure code, not only in CONFIG SET commands.
  • Backups (RDB snapshots) are copied off the server if sessions or other state in Redis matter.
  • High availability needs are defined: for many Django apps, a single instance with persistence and fast restart is enough; otherwise, use replicas with Sentinel or a managed service with automatic failover, and test failover behaviour in Django and Celery.
a Redis restart without surprises1Check the rolecache, sessions, or broker?2Confirm persistencerecent AOF or RDB write3Pause Celery Beatif it is the broker4Restart or fail overoff-peak5Verify clients reconnecterrors, queue lengthA cache restart costs misses; a broker restart can cost tasksdjango-deployment.com
A cold cache after a restart can spike database load; restart off-peak.

Explanation

Redis's configuration is instance-wide: one memory limit, one eviction policy, one persistence setting. Django uses it for data with conflicting needs (disposable cache entries next to tasks that must not be lost), so separating roles is the foundation of a reliable setup. The rest of the checklist protects the instance from outside access, protects the application from a slow or failing Redis through timeouts, and makes pressure visible before it turns into errors.

Edge cases / notes

Managed Redis differences

Managed services may restrict commands (CONFIG), handle persistence through snapshots and replicas instead of AOF, and set default eviction policies such as volatile-lru. Check the defaults and adjust through the provider's parameter settings.

Valkey and Redis licensing

Valkey is an open-source fork of Redis, compatible with its protocol and the Django and Celery clients. The checklist applies to both.

When to automate this

Provision Redis instances from templates that encode role-specific settings (memory, policy, persistence, ACLs), and include Redis metrics and alerts in your standard monitoring stack. Run the restart test during disaster recovery drills.

Next steps

FAQ

Should the Django cache and Celery broker share one Redis instance?

It works for small setups, but separate instances let the cache evict freely while the broker never loses tasks. Separate them as soon as either matters.

What eviction policy should Redis use for Django?

allkeys-lru or allkeys-lfu for a cache-only instance; noeviction for the Celery broker and sessions.

Does Redis need a password on a private network?

Yes. Defence in depth matters, and many breaches start from services assumed to be unreachable. Use ACL users or requirepass.

What Redis metrics should I alert on?

Memory near maxmemory, evictions on non-cache instances, persistence failures, rejected connections, high latency, and growing Celery queues.

Keep going