Technical
Why I Chose DynamoDB Over PostgreSQL for This Project
PostgreSQL is my default database. It is reliable, flexible, and I know it well. But for the PLAI blog platform, I chose DynamoDB instead. The decision came down to one factor: $0/month versus $7/month. Here is the full reasoning.
The Requirement
The blog platform needs to store four entity types: posts, categories, subscribers, and newsletters. The access patterns are simple: list published posts by date, get a post by slug, list subscribers by status, get categories.
No complex joins. No full-text search. No aggregations. No transactions spanning multiple entities. Simple key-value and key-range queries.
The Cost Analysis
DynamoDB (provisioned mode):
25 WCU free tier: enough for ~2M writes/month
25 RCU free tier: enough for ~5M reads/month
25 GB storage: enough for ~500K articles
Monthly cost: $0.00
PostgreSQL (cheapest options):
RDS db.t3.micro: $7.20/month (free tier expires after 12 months)
Neon free tier: limited to 0.5GB, 100 hours/month
Supabase free: 500MB, pauses after 1 week inactive
Self-hosted: requires a VPS ($5-10/month)DynamoDB's free tier does not expire. It is 25 WCU/RCU and 25GB forever. For a blog with moderate traffic, that is more than enough.
When PostgreSQL Wins
I would choose PostgreSQL when:
- The data model has complex relationships (many-to-many, self-referencing)
- I need full-text search (PostgreSQL's built-in FTS is excellent)
- I need ad-hoc queries (SQL is flexible; DynamoDB requires pre-planned access patterns)
- I need transactions across multiple entities
- The team already knows PostgreSQL and does not want to learn DynamoDB
When DynamoDB Wins
DynamoDB wins when:
- Access patterns are known and simple (key-value, key-range)
- Cost must be $0 indefinitely (not just a 12-month free trial)
- You want zero database administration (no backups, no patching, no scaling)
- Read/write performance must be predictable at any scale
- You are already using AWS for other services
The Single-Table Pattern
DynamoDB works best with single-table design. All entities share one table with prefixed keys:
# Posts: pk='POST#my-slug', sk='POST#my-slug'
# Categories: pk='CAT#python', sk='CAT#python'
# Subscribers: pk='SUB#email', sk='SUB#email'This feels wrong to SQL developers, but it means one table, one billing unit, one backup configuration, and predictable performance for all entity types.
The Tradeoffs I Accepted
By choosing DynamoDB, I accepted:
- No ad-hoc SQL queries (I pre-plan all access patterns)
- No joins (I denormalize data and handle relationships in application code)
- A steeper learning curve for the team (single-table design is unintuitive at first)
- Vendor lock-in to AWS (my code depends on DynamoDB-specific APIs)
For this project, those tradeoffs are worth the $0/month price tag.
See the DynamoDB documentation for getting started.
RELATED READING
The Consulting Shift I Am Making In Year Two
After a year of writing and building, my consulting practice is changing shape. Shorter engagements. Sharper outcomes.
ReadThe Frontend Shift: Shipping Less JavaScript In Year Two
A year ago I reached for Next.js for everything. This year I often reach for nothing.
ReadThe Serverless Lesson I Would Write On A Sticky Note
After a year of shipping serverless projects, one rule explains most of the wins and all of the losses.
Read