Senior 10 min · March 06, 2026

RDS vs DynamoDB — Eventual Consistency Failures at Scale

At 50k writes/sec, DynamoDB returned stale balances.

N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Written from production experience, not tutorials.

Follow
Production
production tested
May 23, 2026
last updated
1,554
articles · all by Naren
 ● Production Incident 🔎 Debug Guide ⚙ Triage Commands
Quick Answer
  • RDS: relational, SQL, ACID, vertical scaling, joins, foreign keys
  • DynamoDB: NoSQL, key-value, eventual consistency, horizontal scaling, single-table access patterns
  • Performance: DynamoDB offers single-digit millisecond latency at any scale; RDS latency increases with table joins and index depth
  • Production insight: WRONG choice leads to 10x cost overruns or impossible schema migrations mid-project
  • Biggest mistake: putting relational data (orders, invoices) into DynamoDB and forcing complex joins in app code
✦ Definition~90s read
What is AWS RDS and DynamoDB?

This article compares Amazon RDS (Relational Database Service) and DynamoDB, focusing on how their fundamentally different consistency models break down under production-scale loads. RDS provides ACID transactions with strong consistency by default, using traditional SQL databases like PostgreSQL or MySQL.

Think of RDS like a giant spreadsheet where every row must follow strict column rules — you can't just add a random extra column to one row without updating the whole sheet.

DynamoDB, a NoSQL key-value and document store, offers tunable consistency—eventual (read-after-write) or strongly consistent reads—but defaults to eventual, which can cause stale reads under high concurrency. The core tension: RDS guarantees you always see the latest write, but at the cost of horizontal scaling limits; DynamoDB scales horizontally by partitioning data across nodes, but eventual consistency means a read might return data that’s seconds old, leading to application bugs like duplicate orders or phantom inventory counts when not carefully designed.

You’d choose RDS when you need complex joins, referential integrity, or transactional guarantees—think financial ledgers, ERP systems, or any workload where a stale read is a business failure. DynamoDB excels at internet-scale applications with predictable access patterns: session stores, gaming leaderboards, IoT telemetry, or shopping carts where single-digit millisecond latency at any throughput matters.

The article walks through real-world failure modes: a DynamoDB-backed e-commerce site that double-charges customers during a flash sale because eventual consistency allowed two concurrent reads to see the same inventory count, versus an RDS-backed system that hits connection pool limits under the same load.

At scale, the decision isn’t just about SQL vs NoSQL—it’s about accepting eventual consistency’s trade-offs. RDS scales vertically (bigger instances, read replicas) and hits hard limits around 64 TB and 15,000 connections per instance; DynamoDB scales horizontally to petabytes and millions of requests per second, but you must model your data for single-table designs and handle stale reads with conditional writes or versioning.

The cost models diverge sharply: RDS charges for provisioned compute and storage even when idle; DynamoDB’s on-demand mode can be 10x cheaper for spiky workloads but 3-5x more expensive for steady-state traffic. This article gives you the decision framework: use RDS when consistency is non-negotiable, DynamoDB when scale and latency trump absolute correctness—and never assume eventual consistency is safe without idempotency keys or optimistic locking.

Plain-English First

Think of RDS like a giant spreadsheet where every row must follow strict column rules — you can't just add a random extra column to one row without updating the whole sheet. DynamoDB is more like a folder of sticky notes — each note can have completely different information on it, and you can find any note almost instantly because they're all sorted by a label you chose. One is rigid and relational, the other is flexible and blazing fast. The trick is knowing which one your app actually needs.

Every application needs somewhere to store data. But the database decision you make on day one can haunt you for years — choosing the wrong engine means rewriting queries, hitting performance walls, or paying five times more in cloud costs than you should. AWS gives you two wildly different database philosophies under one roof: RDS (Relational Database Service) and DynamoDB. Understanding the difference isn't just academic — it directly affects how fast your app scales, how much it costs, and how easy it is to maintain when traffic triples overnight.

RDS solves the problem of structured, relationship-heavy data. Your users table needs to join your orders table, which joins your products table — and you need those JOINs to be consistent, transactional, and correct. DynamoDB solves a completely different problem: massive throughput at predictable latency. When you're storing session tokens, IoT sensor readings, or user activity events where you need single-digit millisecond reads at any scale, DynamoDB is built for exactly that.

By the end of this article you'll be able to provision both services with infrastructure-as-code, write idiomatic queries against each, understand the cost model differences, and — most importantly — make a confident architectural decision when someone in a design review asks 'should we use RDS or DynamoDB for this?'

Why RDS and DynamoDB Consistency Models Differ at Scale

RDS (Relational Database Service) and DynamoDB are both managed database services on AWS, but they operate on fundamentally different consistency principles. RDS provides strong consistency by default through ACID transactions, using synchronous replication within a single region. DynamoDB, by contrast, offers configurable eventual consistency for reads, trading immediate accuracy for lower latency and higher throughput — a trade-off that becomes critical at scale.

In practice, DynamoDB's eventual consistency means that after a write, subsequent reads may return stale data for up to one second. This is not a bug but a design choice: DynamoDB replicates data across multiple Availability Zones asynchronously. For reads that require the latest data, you must explicitly request strongly consistent reads, which cost twice the read capacity units and may fail with a 400 error if the replica is unreachable. RDS, using synchronous replication, guarantees that a committed write is immediately visible to all subsequent reads, but this locks you into a single-writer model that limits write throughput.

Choose RDS when your application demands strict consistency — financial transactions, inventory systems, or any workflow where stale reads cause data corruption. Choose DynamoDB when you need single-digit millisecond latency at any scale and can tolerate eventual consistency for most operations, such as session stores, gaming leaderboards, or IoT telemetry. The wrong choice leads to either throttled writes (RDS at scale) or silent data corruption (DynamoDB with strong consistency assumed).

Eventual Consistency Is Not Optional
DynamoDB's default read mode is eventual consistency. If your code assumes strong consistency without explicitly requesting it, you will see stale data under load — and it will be hard to reproduce.
Production Insight
A gaming leaderboard service used DynamoDB's default eventual consistency for score updates. Players saw their own scores disappear after refresh, causing support tickets. The symptom: reads returning stale data up to 2 seconds after write under 10K TPS. Rule: always use strongly consistent reads for user-facing data that must reflect the last write, or design idempotent retry logic.
Key Takeaway
RDS gives you strong consistency but limits write throughput to a single node.
DynamoDB's eventual consistency is a performance feature, not a bug — but you must opt into strong reads when correctness matters.
At scale, the cost of strong consistency (2x RCU, potential 400 errors) often forces you to redesign your data model, not just flip a flag.
RDS vs DynamoDB Consistency at Scale THECODEFORGE.IO RDS vs DynamoDB Consistency at Scale Comparing consistency models, scaling, and cost for multi-region setups RDS: ACID Transactions Strong consistency via single-master replication DynamoDB: Eventual Consistency High availability with multi-region replication lag Scaling: Vertical vs Horizontal RDS scales up; DynamoDB scales out Replication Gap Multi-region writes cause stale reads Cost: Provisioned vs On-Demand RDS fixed capacity; DynamoDB pay-per-request ⚠ Eventual consistency can break read-after-write in multi-region Use DynamoDB strongly consistent reads or RDS read replicas THECODEFORGE.IO
thecodeforge.io
RDS vs DynamoDB Consistency at Scale
Aws Rds Dynamodb

Data Model: Rigid vs Flexible

RDS requires a fixed schema. Every table has defined columns with data types, constraints, and relationships enforced via foreign keys. That's great when your data actually fits a relational model — invoices have line items, users have addresses. But it's painful when you need to add a new attribute to a subset of rows: you either add a nullable column or create a separate extension table.

DynamoDB has no schema constraints (except a required partition key and optional sort key). Items in the same table can have completely different attributes. You can add a new field to one item without touching existing items. That flexibility comes at a cost: no automatic referential integrity, no JOINs, and complex multi-item operations require careful application logic.

The rule: if your data has rich relationships you need to enforce at the database level, pick RDS. If your access patterns are primarily by primary key and you need schema evolution without downtime, DynamoDB wins.

Production Insight
A common mistake is putting highly relational data (user profiles with nested preferences and friends) into DynamoDB and trying to simulate joins via multiple API calls.
That pattern breaks under load — each extra read doubles latency and costs.
If you need relational semantics, stay with RDS.
Key Takeaway
RDS for rigid structure and relationships.
DynamoDB for flexible schema and key-value lookups.
Choose based on access patterns, not hype.

Query Capabilities: SQL vs Key-Value

RDS supports full SQL: SELECT with JOINs, WHERE clauses on any column, GROUP BY, aggregations, subqueries, window functions. You can ask complex analytical questions in a single query. DynamoDB supports only three operations on data: GetItem (by primary key), Query (by partition key + optional sort key conditions), and Scan (full table, expensive). Every other filter must be applied on the client side after retrieving the data.

That means DynamoDB forces you to design your access patterns before you write code. You can't spontaneously run a query to find all users who signed up in March and have at least three orders. You'd need a secondary index (GSI) specifically designed for that query, which adds complexity and cost.

Production reality: most teams adopting DynamoDB underestimate how much their query needs will evolve. They end up adding GSIs, creating materialized views, or streaming to a search engine. The trade-off is predictable performance at scale versus ad-hoc query flexibility.

Production Insight
Adding a new reporting requirement after DynamoDB is in production can trigger a week-long migration to create GSIs and backfill data.
With RDS, you just write a new SQL query.
Don't underestimate the cost of schema on write vs schema on read.
Key Takeaway
RDS: ad-hoc queries, JOINs, aggregation.
DynamoDB: pre-defined query patterns, no JOINs.
Plan your access patterns before choosing DynamoDB.

Scaling: Vertical vs Horizontal

RDS scales vertically — you upgrade the instance size (db.r5.large -> db.r5.xlarge) with some downtime. Read-heavy workloads use read replicas (up to 15 for Aurora). Write scaling is harder: you can't shard writes automatically (unless you implement application-level sharding or use Aurora Serverless v2).

DynamoDB scales horizontally from day one. Each partition key can handle 3000 RCU / 1000 WCU. If you exceed that, DynamoDB splits partitions automatically — but only if your partition key is well-distributed. A hot partition key (e.g., a single tenant that gets 90% of traffic) will throttle regardless of total table capacity.

The scaling axis decision is critical. If you expect unpredictable write spikes (e.g., Black Friday), DynamoDB's on-demand auto-scaling is a huge win. If you need complex transactional writes across multiple tables (e.g., inventory deduction + order creation), RDS's single-writer architecture with ACID is simpler to reason about.

Production Insight
A popular e-commerce site used DynamoDB for its product catalogue. During a flash sale, a single product (hot partition key) hit 10,000 writes/second — DynamoDB throttled all writes to that item, causing order failures.
They fixed it by adding a tenant-level partition key prefix.
Key Takeaway
DynamoDB scales horizontally but demands a good partition key.
RDS scales vertically and with read replicas but has a write bottleneck.
Match scaling model to your workload's read/write ratio and spike pattern.

Performance and Latency

DynamoDB guarantees single-digit millisecond latency for GetItem and Query operations at any scale, as long as your partition key is designed well. Reads served from cache (DAX) can be even faster. RDS latency varies: a simple PK lookup can be 1-5ms, but a complex JOIN with full table scans can be 100ms or more. RDS performance depends on query design, indexes, and instance size.

The key difference: DynamoDB latency is predictable regardless of data size (within partition limits). RDS latency grows with data volume and query complexity. For latency-sensitive applications (user sessions, real-time leaderboards), DynamoDB shines. For analytical queries where 500ms is acceptable, RDS is fine.

Production Insight
A social media app stored user feeds in RDS. As the user base grew, the JOINs to assemble a feed (user + posts + likes + comments) became 200-500ms per request. They moved the feed data to DynamoDB, stored denormalized feed items, and queries dropped to 10ms.
Key Takeaway
DynamoDB for predictable low latency at scale.
RDS for complex queries where latency is secondary to query capability.
If you need both, consider a hybrid approach.

Cost Model: Provisioned vs On-Demand

RDS charges per instance hour + storage + IOPS. You pay for the capacity you provision (even if idle) plus storage costs (GP2, GP3, io1). Reserved instances reduce cost for steady workloads. DynamoDB charges per read/write unit (provisioned or on-demand). On-demand lets you pay per request, ideal for variable workloads. But per-request costs are higher than provisioned for sustained traffic.

A common mistake: underestimating DynamoDB costs for heavy read/write workloads. At scale, a table doing 10,000 writes/second with on-demand pricing can cost over $10,000/month. RDS for similar write throughput would be cheaper with a large instance (e.g., db.r5.12xlarge ~$6,000/month reserved). But RDS can't sustain that write throughput for complex writes involving multiple indexes and triggers.

Key trade-off: DynamoDB costs are directly tied to throughput — you can't have high throughput for cheap. RDS costs are tied to compute — you can get moderate throughput at lower cost, but you hit a vertical scaling ceiling.

Production Insight
A gaming company used DynamoDB on-demand for a leaderboard. Average writes were 100/second, but during tournaments they spiked to 50,000/second. Their monthly bill jumped from $500 to $45,000. They switched to provisioned capacity with auto-scaling and scheduled scaling for tournaments, cutting costs by 60%.
Key Takeaway
DynamoDB: pay per request, expensive at high sustained throughput.
RDS: pay per instance, cheaper at moderate throughput, capped at instance size.
Use DynamoDB on-demand for variable loads, provisioned for steady loads.

When to Use Each: Decision Framework

Here's a practical decision tree: If your data has clear relationships (foreign keys, joins in every query) and you need ACID transactions across multiple entities, choose RDS (specifically Aurora for better performance). If your access patterns are primarily by primary key or a single partition key prefix, you need single-digit millisecond latency at any scale, and you can tolerate eventual consistency (or pay for strong consistency), choose DynamoDB.

If you need both? Use a hybrid: store transactional data (orders, users) in RDS, and operational data (sessions, events, pre-computed aggregates) in DynamoDB. Many production systems do exactly this — the key is not forcing one database to do everything.

There's also a middle ground: Amazon Aurora with MySQL compatibility offers up to 5X throughput of standard MySQL and can handle some key-value patterns with the right index design. Don't ignore it as a compromise if your team is familiar with SQL.

Production Insight
A startup built everything on DynamoDB because they wanted horizontal scalability. Two years later, they needed to generate a financial report that required joining five tables. They couldn't. They ended up streaming data to a Redshift cluster for reporting — an extra operational burden they hadn't planned for.
Key Takeaway
RDS for relationships and complex queries.
DynamoDB for simple access patterns and low latency.
Hybrid is often the right answer.

The Replication Gap: Why Your Multi-Region Setup Is Lying to You

You think because you enabled DynamoDB global tables or RDS cross-Region read replicas that your data is consistent everywhere. It's not. At least, not in the way your application probably assumes. The disconnect between marketing slides and actual behavior has melted production databases for teams who didn't read the fine print.

DynamoDB global tables use last-writer-wins (LWW) conflict resolution. If two simultaneous writes hit different Regions for the same item, the later timestamp wins—period. Your carefully sequenced business logic doesn't matter. RDS cross-Region replicas are asynchronous. A primary failure can drop seconds of committed writes that never made it to the replica. That's not a failover; that's data loss.

You need to audit every request your application makes after a Region failover. Are you reading from the new primary assuming it has the same state as the old? It doesn't. You need idempotency keys, defensive read-repair, and a clear understanding of your actual recovery point objective (RPO), not the one you wish you had.

RegionFailoverAudit.ymlYAML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// io.thecodeforge — devops tutorial

# CloudWatch Alarm: Detect cross-Region replication lag violation
AWSTemplateFormatVersion: '2010-09-09'
Resources:
  ReplicaLagAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: cross-region-replica-lag-critical
      MetricName: ReplicaLag
      Namespace: AWS/RDS
      Dimensions:
        - Name: DBInstanceIdentifier
          Value: prod-us-east-1-replica
      Statistic: Maximum
      Period: 60
      EvaluationPeriods: 2
      Threshold: 5.0  # seconds — most apps assume < 1s
      ComparisonOperator: GreaterThanThreshold
      AlarmActions:
        - arn:aws:sns:us-east-1:123456789012:ops-pager

  DynamoDBReplicationLatency:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: dynamodb-global-table-lag-spike
      MetricName: ReplicationLatency
      Namespace: AWS/DynamoDB
      Dimensions:
        - Name: TableName
          Value: user-sessions
        - Name: GlobalSecondaryIndexName
          Value: session-ttl-index
      Statistic: Average
      Period: 60
      EvaluationPeriods: 3
      Threshold: 1000  # milliseconds — anything above 1s is dangerous
      ComparisonOperator: GreaterThanThreshold
      AlarmActions:
        - arn:aws:sns:us-east-1:123456789012:ops-pager
Output
Alarm 'cross-region-replica-lag-critical' created.
Alarm 'dynamodb-global-table-lag-spike' created.
Both will fire within 2-3 minutes of replication lag exceeding safe thresholds.
Production Trap: LWW Is Not Conflict Resolution
Last-writer-wins does not resolve conflicts—it ignores them. If two Regions modify different attributes of the same item simultaneously, DynamoDB will overwrite one entire item with the other. You lose data silently. Use conditional writes or application-level conflict resolution (like version vectors) if attribute-level merge matters.
Key Takeaway
Cross-Region replication is eventually consistent—until a failover happens, then it's 'maybe consistent'. Design your app to survive that gap.

Cost Tetris: The Signal-to-Noise Ratio Nobody Optimizes

Most teams optimize for read cost or write cost. They miss the real killer: the interaction between access patterns and pricing models. A single DynamoDB scan on a large table can cost more in consumed RCUs than a month of normal traffic. An RDS query that triggers a full table scan on a 500GB table will spike your IOPS bill and degrade every other query.

The problem isn't the database. It's that your application issues queries the database wasn't designed for, and you pay for that mismatch in compute, storage I/O, and unnecessary transfers. You need to instrument every query's cost per execution, not just latency. A fast query that eats 1000 RCUs is worse than a slow query that eats 1.

Start by measuring the actual Cost Per Query (CPQ). For DynamoDB, log the ConsumedReadCapacityUnits and ConsumedWriteCapacityUnits from every response. For RDS, enable Performance Insights and monitor the top SQL patterns by total IO cost. When you see a pattern costing 10x the average, rewrite the query or add an index before the bill arrives.

Don't rely on the AWS Cost Explorer alone. It aggregates too much. You need per-query granularity to catch the silent spenders.

CostPerQueryTracker.ymlYAML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// io.thecodeforge — devops tutorial

# DynamoDB table with cost tracking via Stream + Lambda
AWSTemplateFormatVersion: '2010-09-09'
Resources:
  QueryCostLogger:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.handler
      Runtime: nodejs18.x
      Code:
        ZipFile: |
          exports.handler = async (event) => {
            for (const record of event.Records) {
              if (record.eventName === 'INSERT') {
                const consumed = record.dynamodb.ConsumedCapacity;
                if (consumed) {
                  const cpq = consumed.CapacityUnits / 1; // per item
                  console.log(JSON.stringify({
                    table: record.eventSourceARN.split('/')[1],
                    itemKey: record.dynamodb.Keys,
                    readRCU: consumed.ReadCapacityUnits || 0,
                    writeRCU: consumed.WriteCapacityUnits || 0,
                    costPerQuery: cpq
                  }));
                  // Emit to CloudWatch metric for alerting
                }
              }
            }
          };
      Role: arn:aws:iam::123456789012:role/lambda-dynamodb-cost-logger
      MemorySize: 128
      Timeout: 10

  CostAnomalyAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: high-cost-per-query-anomaly
      MetricName: ConsumedReadCapacityUnits
      Namespace: AWS/DynamoDB
      Dimensions:
        - Name: TableName
          Value: orders-prod
      Statistic: Sum
      Period: 300
      EvaluationPeriods: 1
      Threshold: 10000  # 10k RCU in 5 minutes -> anomaly
      ComparisonOperator: GreaterThanThreshold
Output
Lambda deployed. Each DynamoDB INSERT emits a CloudWatch metric with per-query cost.
Alarm 'high-cost-per-query-anomaly' will trigger if any 5-minute window exceeds 10k RCU.
Senior Shortcut: Tag Your Queries
Add a query tag in your application code (like X-Amzn-DynamoDB-ConsumedCapacity). Then filter your cost logs by tag. You'll instantly see which microservice or endpoint is burning money. This saved one team $12k/month by finding a forgotten background job doing table scans.
Key Takeaway
A fast query that burns 1000 RCUs is more dangerous than a slow query that burns 1. Optimize cost per query, not just latency.

Backup and Restore: RDS vs DynamoDB Recovery Semantics

Backup strategies differ fundamentally between RDS and DynamoDB due to their underlying architectures. RDS offers automated snapshots with point-in-time recovery (PITR) up to 35 days, restoring an entire DB instance. DynamoDB provides on-demand and continuous backups with PITR, but restores to a new table—not an in-place overwrite. This matters because RDS backups are tied to storage volumes via EBS snapshots, enabling cross-region copy and instance cloning for testing. DynamoDB backups are exported to S3 in DynamoDB JSON or Parquet format, allowing granular table-level recovery but no native cross-region replication without AWS Backup integration. RDS restores can take hours for multi-TB instances; DynamoDB restores complete in minutes for most tables. Choose RDS when you need full database rollback with minimal downtime. Choose DynamoDB when table-level isolation and fast recovery of specific datasets are critical.

BackupStrategy.ymlYAML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// io.thecodeforge — devops tutorial

AWSTemplateFormatVersion: '2010-09-09'
Parameters:
  DbType:
    Type: String
    AllowedValues: ["rds", "dynamodb"]
Conditions:
  IsRDS: !Equals [!Ref DbType, "rds"]
Resources:
  BackupPlan:
    Type: AWS::Backup::BackupPlan
    Properties:
      BackupPlan:
        BackupPlanName: CrossRegionPlan
        BackupPlanRule:
          - RuleName: DailySnapshot
            TargetBackupVault: !Ref BackupVault
            ScheduleExpression: "cron(0 5 * * ? *)"
            Lifecycle:
              DeleteAfterDays: 35
Output
exact
Production Trap:
RDS PITR does not support cross-region restores—restore fails if the source KMS key is unavailable in the target region.
Key Takeaway
Restore to new table in DynamoDB, restore same instance in RDS—plan recovery paths accordingly.

Security and Access Control: IAM vs Network Boundaries

RDS and DynamoDB enforce security through different primitives. RDS relies on VPC security groups and subnet groups—network-level access control that isolates database traffic from the public internet. DynamoDB operates outside the VPC boundary, using IAM policies and VPC endpoints (Gateway or Interface) for private access. RDS authenticates via database users and passwords (or IAM database authentication), while DynamoDB uses IAM roles and resource-level policies exclusively. This creates a critical distinction: RDS requires managing database credentials and rotating them; DynamoDB eliminates password management entirely. RDS supports encryption at rest via KMS per DB instance; DynamoDB encrypts by default with an AWS-owned key or customer-managed KMS key per table. For access control, RDS provides granularity at the database user level; DynamoDB at the item and attribute level using fine-grained access control (FGAC) in IAM policies. Choose RDS when compliance demands network segmentation; choose DynamoDB when per-item authorization is required.

SecurityPolicy.ymlYAML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// io.thecodeforge — devops tutorial

AWSTemplateFormatVersion: '2010-09-09'
Resources:
  DynamoDBEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      ServiceName: com.amazonaws.region.dynamodb
      VpcId: !Ref VPC
      PolicyDocument:
        Statement:
          - Effect: Deny
            Principal: '*'
            Action: 'dynamodb:*'
            Condition:
              StringNotEquals:
                'aws:SourceVpce': !Ref VPCEndpointId
  RDSSecret:
    Type: AWS::SecretsManager::Secret
    Properties:
      Name: rds-master-password
      GenerateSecretString:
        SecretStringTemplate: '{"username":"admin"}'
        GenerateStringKey: 'password'
        ExcludePunctuation: True
Output
exact
Production Trap:
DynamoDB FGAC policies can exceed 10KB limit—test all attribute conditions before deployment.
Key Takeaway
RDS secures networks; DynamoDB secures identities—never conflate the two models.

Cost Optimization: Provisioning Waste You Are Paying For

RDS costs come from provisioned IOPS, storage class (gp3, io2), and instance hours—idle instances still burn money. DynamoDB costs from read/write capacity units (RCU/WCU) or on-demand request pricing plus storage per GB. The waste pattern differs: RDS over-provisions IOPS for burst needs, then pays for unused I/O; DynamoDB over-provisions RCU/WCU for peak load, then wastes idle capacity. RDS allows stopping instances (not for Multi-AZ) to save compute costs; DynamoDB has no idle state—you pay per request. Use RDS Reserved Instances for predictable workloads (up to 60% savings). Use DynamoDB reserved capacity (capacity units pre-purchased) for steady-state tables. Monitor RDS CloudWatch metrics for CPU/IOPS headroom >30%—downsize instance class. For DynamoDB, switch to on-demand if RCU utilization drops below 10% for 7 days. RDS storage auto-scaling prevents over-provisioning but spikes costs if misconfigured. DynamoDB auto-scaling targets utilization but incurs write sharding overhead.

CostOptimizer.ymlYAML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// io.thecodeforge — devops tutorial

AWSTemplateFormatVersion: '2010-09-09'
Resources:
  DynamoTable:
    Type: AWS::DynamoDB::Table
    Properties:
      BillingMode: PROVISIONED
      ProvisionedThroughput:
        ReadCapacityUnits: 5
        WriteCapacityUnits: 5
      AutoScalingConfiguration:
        TargetTrackingScalingPolicyConfiguration:
          TargetValue: 70.0
          PredefinedMetricSpecification:
            PredefinedMetricType: DynamoDBReadCapacityUtilization
  RDSInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      DBInstanceClass: db.t3.medium
      StorageType: gp3
      StorageThroughput: 125
      StorageEncrypted: True
      MaxAllocatedStorage: 100
Output
exact
Production Trap:
DynamoDB auto-scaling ignores table-level hot keys—sharding doesn't reduce cost for skewed access patterns.
Key Takeaway
Reserved capacity for steady loads, on-demand for spiky—never mix billing modes without metrics.
● Production incidentPOST-MORTEMseverity: high

The switch broke when we hit 50k writes per second

Symptom
During a marketing campaign, user balance queries returning stale data caused support tickets and a temporary freeze on withdrawals.
Assumption
DynamoDB's eventual consistency would be fine because reads could be reconciled later.
Root cause
DynamoDB's default eventual consistency means two reads for the same key can return different values within a second. Financial systems need strong consistency (which DynamoDB offers, but at half the throughput and higher cost). The team didn't enable strongly consistent reads because they didn't understand the trade-off.
Fix
Enabled DynamoDB's ConsistentRead parameter for all balance queries. This doubled read costs and halved throughput, revealing the underlying scaling issue. They then moved to RDS PostgreSQL with read replicas, which provided ACID transactional reads for balance operations and eventual consistency for reporting queries.
Key lesson
  • Match consistency model to the data: financial data needs strong consistency.
  • Don't chase horizontal scalability before verifying your access patterns fit key-value models.
  • Always test with production-scale traffic before committing to a database decision.
Production debug guideSymptom-to-action grid for common production problems4 entries
Symptom · 01
RDS: Slow queries as data grows
Fix
Check EXPLAIN ANALYZE, add missing indexes, review join patterns. Consider read replicas for reporting queries.
Symptom · 02
DynamoDB: High latency on hot keys
Fix
Review partition key design. A single partition key can throttle at 3000 RCU/1000 WCU. Add partition key spreading (e.g., tenant_id + timestamp).
Symptom · 03
RDS: Connection pool exhaustion
Fix
Increase max_connections? No, that hits OS limits. Use PgBouncer or RDS Proxy. Check idle transactions.
Symptom · 04
DynamoDB: Expensive scans instead of queries
Fix
Scans cost whole-table read capacity. Restructure access patterns to use Query with key conditions. Add GSI if needed but watch for eventual consistency delays.
★ Instant Debug Checklist for Database ChoiceWhen you're seeing unexplained slowdowns or cost spikes, run through this quick list before escalating.
Reads returning stale data
Immediate action
Check if you're using DynamoDB with eventual consistency when strong consistency is required
Commands
DynamoDB: Set `ConsistentRead: true` in your API call; RDS: Check transaction isolation level
Check application code for missing read-after-write guarantees
Fix now
For DynamoDB: use StronglyConsistentRead; for RDS: use SERIALIZABLE isolation if needed
Write throughput throttling+
Immediate action
Check CloudWatch metrics for ThrottledWrite events
Commands
aws dynamodb describe-table --table-name your-table --query 'Table.ProvisionedThroughput'
aws ec2 describe-instances --instance-ids your-db-instance --query 'Reservations[0].Instances[0].EbsOptimized'
Fix now
Increase DynamoDB WCU or switch to on-demand; for RDS, scale up instance size or add read replicas
Unexpected high costs+
Immediate action
Check Cost Explorer for database service spend
Commands
aws ce get-cost-and-usage --time-period Start=$(date -d '-30 days' +%Y-%m-%d),End=$(date +%Y-%m-%d) --granularity DAILY --metrics BlendedCost --filter '{"Dimensions":{"Key":"SERVICE","Values":["Amazon DynamoDB"]}}'
Check if RDS is running on provisioned IOPS (io1/io2) unnecessarily
Fix now
Switch to Aurora Serverless or DynamoDB on-demand for variable workloads
RDS vs DynamoDB: Key Differences
DimensionRDSDynamoDB
Data ModelRelational (tables, rows, columns)Key-value / document (items with attributes)
SchemaFixed, enforced by DBFlexible, no schema per item
Query LanguageSQL (JOINs, aggregations, subqueries)API calls (GetItem, Query, Scan) — limited filtering
ACID TransactionsFull support (across multiple tables)TransactGetItems/TransactWriteItems (max 25 items)
ScalingVertical (upgrade instance) + read replicasHorizontal (partition key based, auto-scaling)
LatencyVaries with query complexity (1-100ms)Single-digit ms for key queries at any scale
ConsistencyImmediate / ACIDEventual by default; Strongly consistent (costs more)
Cost ModelCompute + storage per hourPer read/write unit + storage per GB
Best ForRelational data, complex queries, reportingLow-latency key-value, high throughput, schema-less data

Key takeaways

1
RDS
relational, ACID, SQL, vertical scaling — use for data with relationships and complex queries
2
DynamoDB
NoSQL, key-value, eventual consistency, horizontal scaling — use for high-throughput key-based access at low latency
3
The biggest mistake is forcing one database to do everything
hybrid architectures are common in production
4
Always design access patterns before choosing a database
DynamoDB punishes unprepared query patterns
5
Cost models differ dramatically
DynamoDB per-request can be cheap or expensive depending on traffic patterns; RDS fixed compute cost is predictable

Common mistakes to avoid

5 patterns
×

Using DynamoDB for complex relational data

Symptom
Application code becomes a mess of manual joins across multiple DynamoDB queries, leading to high latency, high costs, and data inconsistency.
Fix
Use RDS (or Aurora) for data that requires JOINs, transactions, and referential integrity. Only use DynamoDB for data with simple key-based access patterns.
×

Choosing RDS for single-table, high-throughput key-value workloads

Symptom
RDS struggles with millions of simple reads per second. Database connection limits, connection pooling overhead, and read replicas add complexity that negates the simplicity of SQL.
Fix
Use DynamoDB with provisioned throughput for workloads where latency matters more than query flexibility. RDS is not designed for massive key-value access.
×

Super-indexing your DynamoDB table

Symptom
Adding many GSIs (global secondary indexes) increases write costs (each GSI consumes table write capacity) and can cause throttling on heavy writes.
Fix
Design access patterns first, then limit GSIs to what's necessary. Often denormalization can eliminate the need for an index.
×

Ignoring partition key design in DynamoDB

Symptom
Throttling on a single partition key (e.g., using a timestamp as partition key causes all writes to go to one partition).
Fix
Use a high-cardinality attribute as partition key (e.g., user_id, order_id) to distribute traffic evenly. Add a sort key for ordering.
×

Not testing with realistic read/write loads before choosing

Symptom
Post-launch performance problems force an emergency migration that costs weeks of development time and exposes data integrity risks.
Fix
Run load tests with production-like traffic on both services (try DynamoDB on-demand and RDS with appropriate instance). Measure latency, cost, and developer effort before committing.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01SENIOR
When would you choose DynamoDB over RDS for a new application?
Q02SENIOR
Explain the concept of a 'hot partition key' in DynamoDB and how to miti...
Q03SENIOR
What are the trade-offs of using DynamoDB's strongly consistent reads vs...
Q04SENIOR
How would you migrate a portion of an RDS-based application to DynamoDB?
Q05SENIOR
Explain the difference between RDS read replicas and DynamoDB global tab...
Q01 of 05SENIOR

When would you choose DynamoDB over RDS for a new application?

ANSWER
Choose DynamoDB when the data access patterns are known upfront and are primarily key-based (e.g., user sessions, player stats, IoT telemetry). The application must tolerate eventual consistency (or pay for strongly consistent reads). The workload must require horizontal scaling with predictable low latency. Also consider if schema flexibility and zero downtime schema changes are important. Do NOT choose DynamoDB if you need complex queries (JOINs, GROUP BY), ad-hoc reporting, strong consistency across multiple entities (ACID transactions spanning tables), or if your data has natural relationships that the DB should enforce. In those cases, RDS is the right choice.
FAQ · 5 QUESTIONS

Frequently Asked Questions

01
Can I use both RDS and DynamoDB in the same application?
02
Which is faster: RDS or DynamoDB?
03
Is DynamoDB cheaper than RDS?
04
Does DynamoDB support ACID transactions?
05
Can I run SQL queries on DynamoDB?
N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Written from production experience, not tutorials.

Follow
Verified
production tested
May 23, 2026
last updated
1,554
articles · all by Naren
🔥

That's Cloud. Mark it forged?

10 min read · try the examples if you haven't

Previous
AWS Lambda and Serverless
6 / 23 · Cloud
Next
AWS VPC and Networking