Aurora Replicas vs RDS Read Replicas for Read Scaling
Problem statement: Your read traffic is outgrowing a single writer and you are scaling out replicas on AWS — but Aurora readers and RDS read replicas scale reads through fundamentally different storage models, and that difference decides your lag floor, your failover speed, and how much the writer pays for each replica you add.
Symptom Identification
You are at the point where this choice matters when you see:
- Read CPU on the writer sustained above 70% while write CPU sits low — reads need their own capacity tier.
- A read:write ratio north of 10:1, where even a handful of replicas materially offloads the primary.
- Post-write reads occasionally returning stale data, forcing a decision about how tight your lag floor must be.
- A plan to add a fifth, tenth, or fifteenth replica, where the per-replica cost to the writer starts to dominate the design.
If any of these apply, the storage model behind your replicas — shared or independent — becomes the deciding factor, not the instance class.
Root Cause Analysis
Aurora and RDS scale reads through opposite storage architectures, and every downstream difference follows from that.
Aurora replicas are compute nodes attached to the same distributed, multi-AZ storage volume as the writer. A reader never replays a WAL stream. When the writer commits, the storage layer makes the change durable across six copies in three AZs, and readers only invalidate and refresh the affected buffer-cache pages. There is no apply queue to fall behind on, which is why AuroraReplicaLag typically reads in single-digit to low-tens of milliseconds even under heavy write load. You address the whole reader tier through a single reader endpoint that load-balances across up to 15 readers, and failover to a reader completes in often under 30 seconds because the promoted node already has the storage attached.
RDS read replicas are physical streaming replicas with their own independent storage. The source ships a WAL stream to each replica, which replays it into a separate EBS volume. That independence is a feature — an RDS replica can live in another region, be a replica of a different engine version, chain as a replica-of-a-replica, and be promoted into a fully standalone writable instance. The cost is a higher lag floor (tens to low hundreds of milliseconds in steady state, more under bulk load) and a per-replica WAL-sender burden on the source.
This is the read-scaling axis of the broader managed vs self-managed read replica decision, and it interacts directly with the read-scaling trade-offs in high-traffic applications you are already navigating.
Architecture: Shared Storage vs Independent Storage
Read-Scaling Scorecard
This table weighs the axes that matter specifically for scaling out reads, with representative numbers.
| Axis | Aurora replicas | RDS read replicas |
|---|---|---|
| Storage model | Shared distributed volume | Independent EBS per replica |
| Typical replica lag | Single-digit to ~20 ms | Tens to low-hundreds ms |
| Max replicas | 15 readers | 15 (RDS Postgres); 5 default (RDS MySQL) |
| Read routing | Reader endpoint (built-in LB) | You load-balance replica endpoints |
| Failover to a replica | Often under 30 s | ~60–120 s (promotion) |
| Cross-region reads | Aurora Global Database | Native cross-region replica |
| Replica of a replica | No (single reader tier) | Yes (cascading) |
| Promote to standalone | No (cluster-bound) | Yes (independent instance) |
| Writer cost per added replica | Minimal (shared storage) | WAL sender + egress per replica |
| Cost dimensions | Instance + storage + I/O | Instance + storage per replica |
The clean rule: choose Aurora when you want the lowest, most predictable lag and the simplest reader scaling inside one region, and choose RDS when you need independent-storage capabilities — cross-region physical replicas, cascading, cross-version, or the ability to promote a replica into a standalone database. For the cross-region case specifically, see cross-region read replicas on RDS.
Step-by-Step Resolution
Step 1: Provision the reader tier
# Aurora: add a reader to an existing cluster (promotion-tier controls failover order)
aws rds create-db-instance \
--db-instance-identifier appdb-aurora-reader-2 \
--db-cluster-identifier appdb-aurora-cluster \
--engine aurora-postgresql \
--db-instance-class db.r6g.2xlarge \
--promotion-tier 1
# RDS: add a streaming read replica to a source instance
aws rds create-db-instance-read-replica \
--db-instance-identifier appdb-rds-replica-2 \
--source-db-instance-identifier appdb-rds-primary \
--db-instance-class db.r6g.2xlargeInline verification: aws rds describe-db-instances shows the new instance reaching available; on Aurora it also appears in the Aurora DB cluster’s reader list.
Step 2: Route reads to the correct endpoint
Point read traffic at the Aurora reader endpoint (which load-balances across readers automatically) or, for RDS, at a load balancer fronting the replica instance endpoints. Never hardcode individual instance endpoints — you lose the ability to add or drain replicas without a redeploy.
# Aurora reader endpoint — resolves across all readers
appdb-aurora-cluster.cluster-ro-xxxx.us-east-1.rds.amazonaws.com:5432Inline verification: Repeated connections to the reader endpoint land on different reader instances (SELECT inet_server_addr(); returns varying IPs).
Step 3: Validate lag under representative load
# Aurora
aws cloudwatch get-metric-statistics --namespace AWS/RDS \
--metric-name AuroraReplicaLag \
--dimensions Name=DBInstanceIdentifier,Value=appdb-aurora-reader-2 \
--period 60 --statistics Maximum \
--start-time "$(date -u -d '15 min ago' +%FT%TZ)" --end-time "$(date -u +%FT%TZ)"Inline verification: Under load, AuroraReplicaLag should stay in the low tens of milliseconds; RDS ReplicaLag should stay within your freshness budget. If it does not, the reader instance class is undersized for the read CPU demand.
Configuration Snippet
Application-side read routing is identical regardless of which you pick — only the endpoint differs. Enforce read-only intent at the routing layer with ORM middleware for automatic query routing:
datasources:
writer:
url: "appdb-cluster.cluster-xxxx.us-east-1.rds.amazonaws.com:5432"
reader:
# Aurora reader endpoint OR RDS replica load balancer
url: "appdb-cluster.cluster-ro-xxxx.us-east-1.rds.amazonaws.com:5432"
read_only: true
max_replication_lag_ms: 100 # Aurora rarely trips this; RDS may under loadVerification and Rollback
-- Both platforms: confirm you are on a reader
SELECT pg_is_in_recovery(); -- t on a reader
-- Aurora: cluster-level lag view
SELECT server_id, replica_lag_in_msec
FROM aurora_replica_status();Rollback: Reader tiers are additive and non-destructive. To back out, remove the reader from the endpoint’s rotation (drain), then delete the instance. On Aurora, deleting a reader has no effect on the shared volume or the writer; on RDS, deleting a replica stops its WAL stream and frees the source’s sender slot.
Edge Cases and Gotchas
Aurora reader endpoint balances connections, not queries
The reader endpoint distributes new connections across readers via DNS, but an established connection stays pinned to one reader. A long-lived pooled connection can concentrate load on a single reader even while the endpoint looks balanced. Recycle pooled connections periodically so the DNS rebalancing actually takes effect.
RDS replica lag spikes on bulk writes have no Aurora equivalent
Because RDS replicas replay WAL, a bulk INSERT/COPY or an un-throttled backfill on the source can push ReplicaLag into seconds while the apply worker catches up. Aurora readers do not replay, so the same bulk write barely moves AuroraReplicaLag. If your workload has bursty bulk-write phases and tight read freshness, that difference alone can decide the platform.
Failover promotion tiers only exist on Aurora
Aurora’s promotion-tier (0–15) controls which reader is promoted first on writer failure. RDS has no equivalent for read replicas — promotion is a manual or Multi-AZ-standby event. If deterministic failover ordering matters, that is an Aurora-only capability. Cross-check your promotion plan against detecting and handling replication lag in real time so you never promote a lagging node.
FAQ
Why is Aurora replica lag so much lower than RDS replica lag?
Aurora readers do not replay a WAL stream. They attach to the same distributed storage volume the writer commits to, so a reader only has to invalidate and refresh cached pages rather than apply log records. That collapses lag to single-digit to low-tens of milliseconds. RDS replicas replay a physical stream into their own independent storage, which lands in the tens-to-hundreds of milliseconds range.
Can RDS read replicas do things Aurora replicas cannot?
Yes. RDS physical replicas have independent storage, so they can be a cross-engine or cross-region replica, be promoted to a fully independent instance, and chain as a replica-of-a-replica. Aurora readers are bound to the shared Aurora storage volume and are a scaling and failover tier, not independent databases, so cross-region reads use Aurora Global Database instead.
Does adding Aurora readers slow down the writer?
Far less than adding RDS streaming replicas does. Because Aurora readers share storage, the writer does not ship a separate WAL stream to each reader, so adding readers up to the limit of 15 has minimal write-path impact. Each additional RDS streaming replica adds a WAL sender and network egress on the source.
Related
← Back to Managed vs Self-Managed Read Replicas
- RDS Read Replicas vs Self-Managed PostgreSQL Replicas — if you might leave AWS’s managed model entirely, this is the control-versus-convenience view.
- Cross-Region Read Replicas on RDS: Cost and Lag Tradeoffs — the independent-storage capability that pushes read scaling across regions.
- Read-Scaling Tradeoffs in High-Traffic Applications — the workload analysis that tells you how many readers you actually need.
- ORM Middleware for Automatic Query Routing — how the application splits reads onto whichever reader endpoint you choose.