Chat over HTTP polling is a bad impression of real-time.
You can fake a chat app by polling an endpoint every second, but it's wasteful, laggy, and doesn't scale — a thousand clients asking "anything new?" on a loop is a thousand pointless requests. Real-time messaging wants a persistent connection that pushes, not a client that keeps knocking.
DjangoChatify is the exercise of doing it properly: WebSockets through Django Channels, with Redis as the channel layer so messages fan out to the right clients instantly.
Real-time isn't faster polling. It's not polling at all.
What "production-ready" meant here.
True push, not polling.
Messages travel over WebSockets via Channels, so delivery is instantaneous and the server isn't answering the same question on a loop.
Containerised and reproducible.
A full Docker Compose setup with a non-root container user, so "works on my machine" and "works in prod" are the same command.
Tested and gated.
Unit and WebSocket tests plus a GitHub Actions pipeline with quality checks, and a
/health/endpoint watching database and Redis.
Redis is the switchboard.
The React client holds a WebSocket to Django Channels; Redis is the channel layer that routes a message to everyone in a room; Postgres persists the history; Gunicorn and Docker package it for deployment.
Redis is the piece that makes it scale beyond a single process: without a shared channel layer, two Django workers can't see each other's clients, so a message sent to worker A never reaches a user on worker B.
Sync Django doesn't hold a connection open.
The friction was conceptual before it was technical: Django's model is request-in, response-out, and a WebSocket is the opposite — a connection that stays open and pushes both ways. Making that work meant the async consumer stack (ASGI, not WSGI) and getting the Redis channel layer configured so broadcasts actually reached other workers.
Once the connection lifecycle and the channel layer were right, everything else — rooms, presence, history — was ordinary Django. The hard part was the paradigm shift, and the tests exist to make sure it stays shifted.
Built to actually run.
The infra choices are the point as much as the chat: a non-root container,
a health-check endpoint, environment-driven config for
DEBUG and ALLOWED_HOSTS, and a CI pipeline that
won't let broken code merge. It's a small app deliberately wearing
production clothes, because that's the part worth practising.
Three things, next time.
Authenticate the socket handshake.
Token auth on connect would tie every message to a real user and lock down rooms properly.
Add delivery and read receipts.
Acknowledgements would make the real-time layer feel complete and expose it to more interesting edge cases.
Load-test the channel layer.
Simulating many concurrent rooms would reveal where Redis and the consumers need tuning before real scale.