---
name: django-postgres-redis
description: "Use when building, refactoring, or reviewing a Django + PostgreSQL + Redis + Celery project (Django, Python, PostgreSQL, Redis, Celery, React). Production guidelines for Django 6 enterprise applications, PostgreSQL connection pooling, Redis caching, and Celery async workers."
license: MIT
metadata:
  source: https://stackitfast.com/rules/django-postgres-redis
  version: "2026-10-04"
---

# Django + PostgreSQL + Redis + Celery — Agent Skill

## When to use this skill
- Any task that scaffolds, modifies, refactors, or reviews code in a Django + PostgreSQL + Redis + Celery codebase.
- Whenever the project depends on Django, Python, PostgreSQL, Redis, Celery, React.
- Apply these guidelines before proposing architecture, database, or deployment changes.

## Guidelines
# Project Architecture & Guidelines (Django + PostgreSQL + Redis + Celery)

## 1. System Architecture
- **Backend Framework**: Django 6.x with WSGI/ASGI (Gunicorn or Uvicorn).
- **Database**: PostgreSQL with connection pooling (PgBouncer or Django native pool, available since 5.1).
- **Caching & Broker**: Redis for Django cache backend, session store, and Celery task broker.
- **Async Worker Queue**: Celery for asynchronous background job execution.

## 2. PostgreSQL Connection Management (Critical)
- Configure the Django (5.1+) database connection pool in `settings.py`:
  ```python
  DATABASES = {
      'default': {
          'ENGINE': 'django.db.backends.postgresql',
          'NAME': env('DB_NAME'),
          'USER': env('DB_USER'),
          'PASSWORD': env('DB_PASSWORD'),
          'HOST': env('DB_HOST'),
          'PORT': env('DB_PORT', default='5432'),
          'OPTIONS': {
              'pool': {
                  'min_size': 2,
                  'max_size': 10,
                  'timeout': 10,
              },
          },
          'CONN_MAX_AGE': 0, # Must be 0 when using native pooling or PgBouncer
      }
  }
  ```
- If deploying behind PgBouncer in `transaction` mode:
  - Disable server-side cursors: `'DISABLE_SERVER_SIDE_CURSORS': True`.
  - Set `CONN_MAX_AGE = 0` to prevent persistent connections from conflicting with the external pooler.

## 3. Redis & Celery Best Practices
- Configure thread safety and broker connection limits:
  ```python
  CELERY_BROKER_URL = env('REDIS_URL')
  CELERY_RESULT_BACKEND = env('REDIS_URL')
  CELERY_RESULT_BACKEND_THREAD_SAFE = True
  CELERY_TASK_ACKS_LATE = True
  CELERY_WORKER_PREFETCH_MULTIPLIER = 1
  ```
- Use `django-redis` with `BlockingConnectionPool` to prevent unbounded Redis socket creation under heavy load:
  ```python
  CACHES = {
      'default': {
          'BACKEND': 'django_redis.cache.RedisCache',
          'LOCATION': env('REDIS_URL'),
          'OPTIONS': {
              'CLIENT_CLASS': 'django_redis.client.DefaultClient',
              'CONNECTION_POOL_CLASS': 'redis.BlockingConnectionPool',
              'CONNECTION_POOL_CLASS_KWARGS': {'max_connections': 50, 'timeout': 20},
          },
      }
  }
  ```

## 4. Background Job & Task Rules
- All Celery tasks MUST be idempotent. Network glitches can cause worker retries.
- Separate CPU-heavy queues from fast I/O queues (e.g., `high-priority`, `default`, `analytics`).
- Pass record IDs (primary keys) to Celery tasks instead of serialized model instances to prevent stale data race conditions.

## 5. Common Pitfalls to Avoid
- ❌ Calculating connection pool without worker count: Total connections = `(Gunicorn Workers × DB Pool) + (Celery Workers × Concurrency)`. Ensure this is within PostgreSQL `max_connections`.
- ❌ Unindexed Foreign Keys: Always ensure database models define `db_index=True` on filtered columns.
- ❌ Blocking the HTTP Request Loop: Offload any third-party API calls, email dispatches, or heavy reporting to Celery.

## 6. Testing Conventions
- Use `pytest` + `pytest-django` with `--reuse-db` for fast local iteration; drop `--reuse-db` in CI to catch migration drift.
- Use `factory_boy` for model factories instead of fixtures — fixtures rot as schemas evolve, factories don't.
- Test Celery tasks synchronously with `CELERY_TASK_ALWAYS_EAGER = True` in the test settings module, and assert idempotency by calling the task twice.
- Cover connection-pool-sensitive code paths (long transactions, `CONN_MAX_AGE` interactions) with integration tests against a real Postgres instance, not SQLite.

## 7. Git Workflow & PR Conventions
- Conventional Commits (`feat:`, `fix:`, `refactor:`) with the Django app name in scope, e.g. `fix(billing): correct Stripe webhook idempotency key`.
- Every migration file ships in the same PR as the model change that generated it — never a follow-up PR.
- Run `python manage.py makemigrations --check --dry-run` in CI to block unmigrated model changes from merging.
- Require `pytest` and `ruff check .` green before merge; squash-merge to keep `main` bisectable.

## Source
Maintained at https://stackitfast.com/rules/django-postgres-redis — also available as AGENTS.md, CLAUDE.md, and Cursor .mdc.