0x55aa
← Back to Blog

RDS vs DynamoDB: The Database Choice That'll Keep You Up at Night πŸ—„οΈπŸ˜°

β€’15 min read

RDS vs DynamoDB: The Database Choice That'll Keep You Up at Night πŸ—„οΈπŸ˜°

Real talk: The first time my CTO asked "Should we use RDS or DynamoDB for this?", I froze. I had no idea. So I did what any developer would do - I Googled "RDS vs DynamoDB" and picked the one that sounded cooler.

I chose DynamoDB. It was the WRONG choice. 😭

Six months later, we had to migrate 2 million rows to RDS because DynamoDB couldn't handle our complex queries. The migration took 3 weeks, cost $12,000 in consulting fees, and nearly killed our product launch!

Welcome to AWS database hell - where one wrong decision costs you months of regret!

What's the Actual Difference? (No BS Version) πŸ€”

RDS (Relational Database Service):

Think: Traditional SQL database (Postgres, MySQL, etc.)
Hosted by: AWS (managed for you)
Best for: Complex queries, relationships, transactions
Cost: Predictable (you pay for instance size)

DynamoDB:

Think: Giant key-value store / NoSQL
Hosted by: AWS (fully serverless)
Best for: Simple queries, massive scale, speed
Cost: Unpredictable (you pay per request)

Translation: RDS is a Ferrari - powerful, handles curves well, but you gotta maintain it. DynamoDB is a Tesla - autopilot enabled, futuristic, but if you drive it wrong you'll crash! 🏎️⚑

My $12,000 Mistake: When I Chose Wrong πŸ’Έ

The project: E-commerce backend with products, users, orders, reviews, and inventory.

What I did (wrongly):

"DynamoDB is serverless! It scales infinitely! It's the future!" I convinced myself.

// My naive DynamoDB design
const schema = {
  Users: { PK: 'USER#id', SK: 'PROFILE' },
  Products: { PK: 'PRODUCT#id', SK: 'DETAILS' },
  Orders: { PK: 'ORDER#id', SK: 'METADATA' },
  Reviews: { PK: 'PRODUCT#id', SK: 'REVIEW#timestamp' },
  Inventory: { PK: 'WAREHOUSE#id', SK: 'PRODUCT#id' }
};

// "Single table design is best practice!" they said...

What happened in production:

Month 1: Everything's great! Fast queries! Low costs!

Month 2: Product manager asks "Can users search products by multiple filters?"

Me: "Ummm... that requires a Scan... which costs $$$..." 😰

Month 3: "Can we generate a report of orders by date range, filtered by product category, grouped by customer region?"

Me: "That's... not possible with DynamoDB's query patterns..." πŸ€¦β€β™‚οΈ

Month 4: "Can we do JOIN queries between orders and products?"

Me: "We need to migrate to RDS. Yesterday." 😭

The migration cost:

  • Engineering time: 3 weeks (2 developers)
  • AWS costs: Data transfer + dual-running databases = $4,000
  • Consultant to design RDS schema: $8,000
  • Total: $12,000 πŸ’Έ
  • Emotional damage: Priceless

When to Use RDS (And Save Yourself Pain) βœ…

Use RDS when you have:

1. Complex Relationships Between Data

-- This is EASY in RDS:
SELECT u.name, COUNT(o.id) as order_count, SUM(o.total) as revenue
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE o.created_at > '2026-01-01'
GROUP BY u.id
HAVING revenue > 1000
ORDER BY revenue DESC;

-- In DynamoDB? Good luck! 😱
-- You'd need: Multiple queries, client-side joins, tons of code!

In production, I've deployed dozens of RDS databases. The moment you need JOINs, use RDS! Don't even think about DynamoDB!

2. Ad-Hoc Queries and Analytics

-- Product manager at 4 PM: "Quick, I need a report!"
SELECT
  p.category,
  COUNT(*) as product_count,
  AVG(r.rating) as avg_rating
FROM products p
LEFT JOIN reviews r ON p.id = r.product_id
WHERE p.created_at BETWEEN '2026-01-01' AND '2026-01-31'
GROUP BY p.category;

-- RDS: Copy-paste into pgAdmin, run query, done! βœ…
-- DynamoDB: Write custom Lambda, deploy, debug, cry 😭

When architecting on AWS, I learned: If business analysts need to run custom queries, you NEED RDS. DynamoDB will drive them insane!

3. ACID Transactions That Actually Matter

// Banking app - MUST be atomic!
async function transferMoney(fromUserId, toUserId, amount) {
  const client = await pool.connect();

  try {
    await client.query('BEGIN');

    // Deduct from sender
    await client.query(
      'UPDATE accounts SET balance = balance - $1 WHERE user_id = $2',
      [amount, fromUserId]
    );

    // Add to receiver
    await client.query(
      'UPDATE accounts SET balance = balance + $1 WHERE user_id = $2',
      [amount, toUserId]
    );

    await client.query('COMMIT');
    // Either BOTH succeed or BOTH fail! 🎯
  } catch (err) {
    await client.query('ROLLBACK');
    // Money never lost or duplicated! βœ…
  }
}

DynamoDB transactions:

  • Limited to 25 items
  • More expensive
  • More complex to implement
  • Not as battle-tested

My rule: Financial transactions? Healthcare records? Inventory management? Use RDS! πŸ’°

4. You're Migrating from Existing SQL Database

# Migrating MySQL β†’ RDS MySQL: 1 day
pg_dump old_database | psql new_rds_database
# Done! βœ…

# Migrating MySQL β†’ DynamoDB: 3-6 months
# - Redesign entire data model
# - Rewrite all queries
# - Change application logic
# - Test everything again
# - Pray it works πŸ™

A serverless pattern that saved us: If you already have SQL, stick with SQL! Don't fix what ain't broke!

When to Use DynamoDB (And Actually Win) πŸš€

Use DynamoDB when you have:

1. Massive Scale with Simple Access Patterns

// Simple key-value lookups at 100K req/sec
const params = {
  TableName: 'Users',
  Key: { userId: '12345' }
};

const result = await dynamodb.get(params).promise();
// Response time: 5ms ⚑
// Cost: $0.00025 per 1000 reads

// Same in RDS at 100K req/sec?
// - Need huge instance ($$$)
// - Read replicas ($$$)
// - Connection pooling nightmares
// - DBA on speed dial 😰

In production, I've deployed DynamoDB for session storage handling 500K concurrent users. RDS would've cost 10Γ— more!

2. Serverless Architecture (Lambda + API Gateway)

// DynamoDB + Lambda = Perfect match! πŸ’‘
exports.handler = async (event) => {
  const { userId } = event.pathParameters;

  // No connection pool needed!
  const result = await dynamodb.get({
    TableName: 'Users',
    Key: { userId }
  }).promise();

  return {
    statusCode: 200,
    body: JSON.stringify(result.Item)
  };

  // Cold start: 200ms
  // Cost: Pennies
  // Scaling: Infinite βœ…
};

// Same with RDS + Lambda = Connection pool hell! 😭
// - Need RDS Proxy ($$$)
// - Connection timeouts
// - Cold start: 2-3 seconds
// - "Too many connections" errors

My serverless apps: 100% DynamoDB. Zero connection management headaches! πŸŽ‰

3. Event-Driven Workloads with DynamoDB Streams

// DynamoDB Streams trigger Lambda on EVERY change!
exports.handler = async (event) => {
  for (const record of event.Records) {
    if (record.eventName === 'INSERT') {
      const newUser = record.dynamodb.NewImage;

      // Automatically send welcome email! πŸ“§
      await sendWelcomeEmail(newUser.email.S);

      // Update analytics! πŸ“Š
      await trackNewUser(newUser);
    }
  }
};

// RDS equivalent: Set up triggers, CDC, Debezium, Kafka...
// Complexity level: INSANE 🀯

When architecting on AWS, I learned: Event-driven patterns? DynamoDB Streams are GOLD! Way easier than RDS triggers!

4. Global Applications (Multi-Region)

// DynamoDB Global Tables = one-click multi-region! 🌍
// Write in US East β†’ Automatically replicated to EU, Asia
// Latency: <100ms anywhere in the world!

// RDS multi-region?
// - Manual read replicas
// - Cross-region replication lag
// - Complex failover logic
// - DBA salary: $150K/year πŸ’Έ

My production global app: DynamoDB Global Tables. Works like magic! No DBA required!

The Cost Reality Check πŸ’°

Let's compare real costs for a typical app:

Scenario: 10M requests/month, 100GB data, moderate traffic

RDS Costs:

RDS db.t3.medium (2 vCPU, 4GB RAM):
- Instance: $0.068/hour Γ— 730 hours = $49.64/month
- Storage: 100GB Γ— $0.115/GB = $11.50/month
- Backups: 100GB Γ— $0.095/GB = $9.50/month
- Total: $70.64/month

RDS db.r5.large (for high traffic):
- Instance: $0.24/hour Γ— 730 hours = $175.20/month
- Storage: 100GB Γ— $0.115/GB = $11.50/month
- Backups: 100GB Γ— $0.095/GB = $9.50/month
- Total: $196.20/month

Predictable, fixed costs! βœ…

DynamoDB Costs (On-Demand):

10M requests/month:
- Reads (7M): 7M Γ— $0.25/M = $1.75
- Writes (3M): 3M Γ— $1.25/M = $3.75
- Storage: 100GB Γ— $0.25/GB = $25
- Total: $30.50/month πŸŽ‰

BUT... if queries are inefficient:
- Scans instead of queries: 10Γ— more RCU consumed
- Cost: $175/month 😰

AND... if traffic spikes 10Γ—:
- 100M requests/month
- Reads: $17.50
- Writes: $37.50
- Total: $280/month πŸ’Έ

Unpredictable, usage-based costs! ⚠️

My Production Costs (Real Numbers):

Small API (5K users):

  • RDS: $70/month (fixed)
  • DynamoDB: $12/month (variable) βœ… DynamoDB wins!

Medium API (100K users):

  • RDS: $200/month (scaled instance)
  • DynamoDB: $85/month (optimized queries) βœ… DynamoDB wins!

Large API (1M users, complex queries):

  • RDS: $500/month (read replicas + larger instance)
  • DynamoDB: $1,200/month (many GSIs + scans) 😭 RDS wins!

Enterprise analytics (complex reporting):

  • RDS: $800/month (powerful instance)
  • DynamoDB: Not feasible (can't do complex JOINs) 🚫 RDS is only option!

The Hybrid Approach (What I Actually Use) 🎯

Real talk: Most production apps need BOTH!

My e-commerce architecture:

// DynamoDB for hot path (user-facing, fast queries)
- User sessions β†’ DynamoDB ⚑
- Shopping carts β†’ DynamoDB ⚑
- Product catalog (read-heavy) β†’ DynamoDB ⚑

// RDS for complex logic (admin, analytics)
- Order management β†’ RDS (JOINs needed) πŸ“Š
- Inventory tracking β†’ RDS (ACID transactions) πŸ’°
- Admin reports β†’ RDS (ad-hoc queries) πŸ“ˆ
- Financial data β†’ RDS (compliance) πŸ”’

// Sync between them with Lambda + DynamoDB Streams!
DynamoDB order created β†’ Lambda β†’ Insert into RDS

Results:

  • User-facing APIs: <50ms (DynamoDB)
  • Admin dashboards: 200-500ms (RDS)
  • Monthly cost: $180 (vs $800 with RDS-only!)
  • Best of both worlds! πŸŽ‰

The Decision Matrix (Actually Useful) πŸ“Š

Choose RDS if you have:

  • βœ… Complex JOINs across multiple tables
  • βœ… Ad-hoc queries from business users
  • βœ… ACID transactions are critical
  • βœ… Existing SQL database to migrate
  • βœ… Moderate traffic (<10K req/sec)
  • βœ… Predictable, fixed costs preferred
  • βœ… SQL skills on team (no NoSQL experience)

Choose DynamoDB if you have:

  • βœ… Simple key-value or single-table queries
  • βœ… Massive scale (>100K req/sec)
  • βœ… Serverless architecture (Lambda)
  • βœ… Event-driven workflows
  • βœ… Global multi-region needs
  • βœ… Variable traffic (pay-per-use cheaper)
  • βœ… NoSQL experience on team

Use BOTH if you have:

  • βœ… Hot path + cold path separation
  • βœ… User-facing + admin/analytics split
  • βœ… Budget for hybrid architecture
  • βœ… Engineering team that can manage both
  • βœ… Real-time + historical data needs

Common Mistakes That'll Wreck You πŸͺ€

Mistake #1: Treating DynamoDB Like SQL

// WRONG: Querying DynamoDB with filters (expensive!)
const result = await dynamodb.scan({
  TableName: 'Products',
  FilterExpression: 'category = :cat AND price < :price',
  ExpressionAttributeValues: {
    ':cat': 'Electronics',
    ':price': 100
  }
}).promise();

// Scans ENTIRE table! πŸ’ΈπŸ’ΈπŸ’Έ
// 1M items = 1M read units consumed!

// RIGHT: Use proper partition key + GSI
const result = await dynamodb.query({
  TableName: 'Products',
  IndexName: 'CategoryPriceIndex',
  KeyConditionExpression: 'category = :cat',
  FilterExpression: 'price < :price',
  ExpressionAttributeValues: {
    ':cat': 'Electronics',
    ':price': 100
  }
}).promise();

// Only queries items with category='Electronics'! βœ…

Mistake #2: Running RDS Without Read Replicas (High Traffic)

// WRONG: Single RDS instance for 50K users
// - All reads + writes hit one database
// - Connection pool maxes out
// - Queries slow down
// - Users complain 😭

// RIGHT: RDS primary + read replicas
const writePool = new Pool({
  host: 'primary.rds.amazonaws.com',
  // All writes go here
});

const readPool = new Pool({
  host: 'replica.rds.amazonaws.com',
  // All reads go here (90% of traffic!)
});

// Writes: 5K req/sec β†’ Primary βœ…
// Reads: 45K req/sec β†’ Replicas βœ…
// Performance: FAST ⚑

Mistake #3: Not Using Aurora (If You Need RDS)

Regular RDS:

db.r5.2xlarge: $0.96/hour = $700/month
Read replicas: $700/month each
Total: $1,400+/month

Aurora (MySQL/Postgres compatible):

Same workload: $300-500/month
Features:
  - 5Γ— faster than MySQL
  - Auto-scaling storage
  - 15 read replicas (vs 5 for RDS)
  - Faster backups
  - Better failover

When architecting on AWS, I learned: If you're using RDS, use Aurora! It's cheaper AND faster! πŸš€

Mistake #4: DynamoDB Without On-Demand Pricing

// Provisioned capacity (old way):
// - Guess: "We need 1000 RCU and 500 WCU"
// - Pay 24/7 even if unused
// - Traffic spike? Throttling! 🚫
// - Over-provisioned? Wasted $$$! πŸ’Έ

// On-Demand (modern way):
// - Pay only for requests used
// - Auto-scales to any traffic
// - No throttling (unless you hit AWS limits)
// - Perfect for unpredictable workloads! βœ…

// When to use Provisioned:
// - Predictable, steady traffic
// - High volume (>1M req/month)
// - Can save 40-60% vs on-demand

// When to use On-Demand:
// - Unpredictable traffic
// - Low/medium volume
// - Serverless apps
// - Development/staging

The Migration Stories (Learn from My Pain) 😰

Migration 1: RDS β†’ DynamoDB (Success)

Scenario: Simple user authentication service

Before (RDS):

  • 1 table: users (id, email, password_hash)
  • Simple queries: SELECT * FROM users WHERE email = ?
  • Cost: $70/month
  • Traffic: 10K users, 50K req/day

After (DynamoDB):

  • 1 table: Users (PK: email, attributes: id, password_hash)
  • Simple query: dynamodb.get({ Key: { email } })
  • Cost: $8/month βœ…
  • Performance: 10Γ— faster! ⚑

Migration time: 2 days Regrets: None! πŸŽ‰

Migration 2: DynamoDB β†’ RDS (Disaster)

Scenario: E-commerce platform (my $12K mistake!)

Before (DynamoDB):

  • 5 tables: Users, Products, Orders, Reviews, Inventory
  • Complex queries needed: Multi-filter search, reports, analytics
  • Cost: $120/month (but queries were hacked together!)
  • Pain level: EXTREME 😭

After (RDS):

  • Normalized schema: 8 tables with proper relationships
  • Clean queries: Proper JOINs, GROUP BY, aggregations
  • Cost: $180/month
  • Happiness level: HIGH 😊

Migration time: 3 weeks Lessons learned: Choose the right tool FIRST! 🎯

Quick Start: How to Actually Decide πŸš€

Step 1: Ask yourself these questions:

  1. Query patterns: Simple key-value OR complex JOINs?
  2. Scale: <10K req/sec OR >100K req/sec?
  3. Team skills: SQL experts OR NoSQL experience?
  4. Budget: Fixed costs OR variable costs?
  5. Analytics: Ad-hoc queries needed OR predefined queries only?

Step 2: Use this flow chart:

Does your app need complex JOINs?
  YES β†’ RDS βœ…
  NO β†’ Continue...

Will traffic exceed 50K req/sec?
  YES β†’ DynamoDB βœ…
  NO β†’ Continue...

Do you have existing SQL database?
  YES β†’ RDS βœ…
  NO β†’ Continue...

Is it a serverless architecture?
  YES β†’ DynamoDB βœ…
  NO β†’ Continue...

Do business analysts need to run queries?
  YES β†’ RDS βœ…
  NO β†’ DynamoDB βœ…

Step 3: Prototype BOTH (seriously!):

# Spend 1 day testing each
# - Set up RDS instance
# - Set up DynamoDB table
# - Write sample queries
# - Test performance
# - Calculate costs

# 8 hours now saves 3 months later! ⏰

The Bottom Line πŸ’‘

There's no "better" database - only the RIGHT one for YOUR use case!

Use RDS when:

  • Relationships matter
  • Queries are complex
  • SQL skills exist
  • Predictable costs needed

Use DynamoDB when:

  • Speed is critical
  • Scale is massive
  • Serverless is goal
  • Simple queries suffice

Use BOTH when:

  • Budget allows
  • Hybrid makes sense
  • Best of both worlds needed

The truth I learned the hard way:

Choosing the wrong database is worse than picking a bad programming language. You can refactor code in weeks. You can't easily migrate databases without downtime, pain, and $$$! 😭

When architecting our e-commerce backend, the database decision was the MOST IMPORTANT architectural choice we made. Get it right, and you'll scale smoothly. Get it wrong, and you'll spend months refactoring instead of shipping features! πŸš€

Start with the simplest option that meets your needs. Don't over-engineer. And for the love of all that is holy, prototype FIRST before committing! πŸ™

Your Action Plan 🎯

This week:

  1. List your app's top 10 queries
  2. Check if they need JOINs or are simple key-value
  3. Estimate traffic (current + 2 years out)
  4. Calculate costs for both RDS and DynamoDB

This month:

  1. Build a proof-of-concept with your top choice
  2. Test with realistic data (1M+ rows)
  3. Measure performance and costs
  4. Make final decision based on DATA, not hype

This quarter:

  1. Optimize your chosen database
  2. Set up monitoring and alerts
  3. Plan for scale (read replicas or DynamoDB optimization)
  4. Document your data model for the team
  5. Sleep well knowing you chose wisely! πŸ˜΄βœ…

Resources Worth Your Time πŸ“š

Tools I use daily:

Reading list:

Real talk: The best database strategy is choosing based on YOUR access patterns, not what's trendy!


Chose the wrong database? Connect with me on LinkedIn and share your migration horror stories!

Want to see my database architectures? Check out my GitHub - I've built apps with both RDS and DynamoDB!

Now go forth and choose wisely! πŸ—„οΈβœ…


P.S. If you've never actually prototyped both databases before choosing, you're gambling with your future self's sanity. Spend 1 day testing BOTH. Future you will thank you! πŸ™

P.P.S. I once met a developer who migrated from RDS to DynamoDB and then BACK to RDS within 6 months. He now works at a startup that uses MongoDB. Some people never learn... πŸ˜‚πŸ’€