The Problem That Kept Coming Back
Every project eventually needed chat. Customer support, collaboration, real time updates. I built chat for one project, then another, then another. Each time I wrote similar code with slightly different data models. It was wasteful.
I decided to build chat infrastructure once and reuse it everywhere. A single DynamoDB table that could power real time messaging for any application.
The Single Table Design
The entire chat system lives in one DynamoDB table. The key structure is simple.
The primary key is the conversation ID combined with a timestamp as the sort key. This lets me query all messages in a conversation in order. The global secondary index maps users to their conversations so I can show someone their full chat history with a single query.
That is it. Two access patterns. One table. No joins, no complex queries, no denormalization headaches.
Why DynamoDB
PostgreSQL would have worked but it would have required connection pooling, read replicas at scale, and ongoing maintenance. DynamoDB needs none of that. You provision the throughput and it handles the rest.
For chat, the access patterns are well known and stable. You always query by conversation or by user. Those patterns never change. DynamoDB rewards you when you know your access patterns upfront and design around them.
Real Time Delivery
Messages written to DynamoDB trigger a stream event. A Lambda picks up the event and broadcasts the message to all connected WebSocket clients through API Gateway. The client receives the message without polling.
The system handles disconnections gracefully. If a client drops, the message stays in DynamoDB and gets delivered when they reconnect.
What I Built
A reusable chat module that any application can integrate. The same infrastructure powers chat across multiple projects with zero changes to the core code. Each application gets its own conversation namespace but shares the same DynamoDB table, the same WebSocket endpoint, and the same broadcast logic.
Top comments (0)