< back to blog

Using a cache to accelerate DynamoDB (or replace it)

A cache can reduce DynamoDB latency, absorb hot-key reads, or hold truly disposable data—but only when the workload's data-loss boundaries allow it.

It’s no secret that I’m a big DynamoDB fan. I started using it because it worked well with serverless applications. I grew to love it for its consistent, predictable performance. That experience has made me wary of services with highly variable performance.

DynamoDB is still my first choice for many persistence needs, but it isn’t the right tool for every job. Even when it is a good fit, another service may improve a particular part of the workload.

A cache can play two very different roles. It can sit in front of DynamoDB and serve repeat reads while DynamoDB remains the durable source of truth. Or it can hold the only copy of some data. That second role is safe only when the data is disposable or fully recoverable and its loss won’t violate application correctness.

We’ll use that boundary to examine three decisions:

  • Reduce read latency with a cache.
  • Absorb concentrated read traffic before it reaches DynamoDB.
  • Reduce costs for write-heavy, ephemeral data.

The service capabilities, limits, and prices below describe the landscape when this post was published in November 2022. Use the decision framework—not the dollar figures—as current architecture guidance.

Use cache-aside when DynamoDB latency is too much for the request path

The most obvious reason to put a cache in front of DynamoDB is speed. Blazing speed is the raison d’être of caches.

That may sound odd because I often talk about DynamoDB’s fast performance. The distinction is between absolute speed and predictable speed.

I often use a conceptual chart like this one:

Conceptual chart in which MySQL latency rises with data size or concurrent queries while DynamoDB latency stays flat

MySQL, or another relational database, often slows as the amount of data or the number of concurrent queries grows. DynamoDB’s performance remains consistent as the table grows.

That consistency matters. You don’t want to perform costly refactors and optimizations every time database usage increases. With DynamoDB, you can expect the same single-digit millisecond response time when your application launches and years later when it has significantly more users.

Some request paths still need faster reads. E-commerce users want fast page loads, and gaming users want responsive gameplay. In a microservices architecture, one service may be among many that must answer before a page can load. A few milliseconds at each step can accumulate.

This is an augmentation pattern. DynamoDB still supplies the durability and availability the application requires. The cache keeps frequently requested data in faster, less durable RAM and serves it when present.

Design the miss path first. When an entry is absent or expired, the application should retrieve it from DynamoDB and repopulate the cache. The application also needs a deliberate freshness policy so a cached value doesn’t outlive the staleness the workflow can tolerate.

Use a cache to absorb hot-key reads

A second reason to use a cache with DynamoDB is scale.

*Record scratch*

You may be thinking, “Wait a minute. DynamoDB’s claim to fame is scalability. Why do we need a cache to improve it?”

You’re right: DynamoDB can handle incredible scale. Jeff Barr’s recap of Amazon Prime Day 2022 notes that Amazon retail made trillions of DynamoDB requests over Prime Day and peaked at more than 105 million requests per second.

The important question is how that traffic is distributed. DynamoDB scales horizontally by dividing a table into partitions across many machines.

DynamoDB distributing a table across three storage partitions

At the time of writing, DynamoDB kept each partition at no more than 10 GB. It stored those partitions alongside partitions from other tables on shared storage nodes within a region. DynamoDB therefore enforced per-partition throughput limits: 1,000 write units or 3,000 read units per second.

Those limits aren’t a problem for many workloads. An individual customer is unlikely to write to an e-commerce application 1,000 times per second, and a game character is unlikely to require 3,000 reads per second. A cache might reduce latency in those cases, but it isn’t necessary to distribute the load.

Some applications have a different access pattern. A popular post on a social network may receive millions of impressions in a short period. A hot deal on a shopping site may draw an extreme traffic spike. These are examples of a Zipfian distribution, in which the most popular items receive orders of magnitude more traffic than the average item.

A central cache can absorb those repeated reads before they reach the hot DynamoDB partition. In this pattern, every durable write still goes to DynamoDB. Only reads that find the item in the cache avoid the partition limit.

This is another augmentation pattern. A read-aside cache checks the cache first, fetches a missing record from DynamoDB, and then caches that record for a later request. DynamoDB remains the durable source while the cache reduces repeated read pressure.

Replace DynamoDB only when the data can disappear

The first two patterns keep DynamoDB as the system of record. Replacing it with a cache changes the failure model, so cost can’t be the first decision.

Before comparing prices, ask:

  • Can the application remain correct if the entire cached dataset disappears?
  • Can it rebuild the data from another source, or is the data genuinely disposable?
  • Does every item have a time to live (TTL) that matches the workflow?
  • What happens when a cache read, write, or increment fails?

Session data qualifies only when forced reauthentication or another recovery path is acceptable. Rate-limit counters require even more care: if losing them would weaken a security, abuse-prevention, or billing boundary, they aren’t disposable state.

If any answer leaves correctness or recovery unclear, keep a durable database in the design.

The November 2022 cost model

With that boundary established, we can look at the cost argument as it stood in 2022.

DynamoDB charged for read units and write units rather than instance resources such as CPU, RAM, or disk input/output operations per second (IOPS). One read unit covered 4 KB of strongly consistent data, while one write unit covered 1 KB. DynamoDB rounded up, so reading or writing 100 bytes still consumed a full unit.

DynamoDB offered two billing modes. In Provisioned Capacity mode, you paid an hourly rate for the read and write units the application needed each second. In On-Demand mode, you didn’t specify capacity up front and instead paid for the units the application used.

At the time, On-Demand mode cost about seven times as much as fully utilized Provisioned Capacity. Full utilization was unlikely, however. Depending on workload predictability, Provisioned Capacity utilization could range from 20% on the low end to 70% on the high end.

The following estimates show the cost to write 1 GB to DynamoDB using On-Demand mode and Provisioned Capacity at 50% and 100% utilization.

DynamoDB write-cost estimate (USD per GB)

DynamoDB write-cost estimate (USD per GB)
Object sizeOn-DemandProvisioned at 50% utilizationProvisioned at 100% utilization
0.5 KB (2 million writes per GB)$2.50$0.72$0.36
1 KB (1 million writes per GB)$1.25$0.36$0.18

The post’s estimates use the us-east-1 prices available in November 2022.

Even in the ideal case—exactly 1 KB objects and fully utilized provisioned capacity—DynamoDB cost about $0.18 per GB written. At 50% utilization with 0.5 KB objects, the estimate rose to $0.72 per GB. On-Demand mode or smaller items pushed the per-GB cost higher.

The prose published with this chart states that Momento charged $0.50 per GB of data read or written. The chart’s Momento series has no numeric labels, but its two green bars appear near $0.18–$0.20 per GB. The source doesn’t explain the difference, so both are preserved here as conflicting historical evidence rather than reconciled into one value.

Historical bar chart comparing the post’s 2022 write-cost estimates for Momento and three DynamoDB billing scenarios across 0.5 KB and 1 KB objects; the unlabeled Momento bars appear near $0.18–$0.20 per GB
Historical comparison from the original post. Its unlabeled Momento bars appear near $0.18–$0.20 per GB, which conflicts with the accompanying prose’s $0.50-per-GB figure.

Because of that unresolved discrepancy, the source doesn’t support a precise Momento-versus-DynamoDB savings claim. More importantly, a price comparison doesn’t mean you should move a database workload into a cache. DynamoDB provides durability, availability, and indexing properties that a cache doesn’t. The architecture decision comes before the bill.

A cache can fit a high-volume write workload when the data is ephemeral, fully regenerable, and independent of durable correctness. In that narrow case, moving the workload may reduce latency and cost. If the application can’t tolerate loss, expiration, or an unavailable cache, use the cache alongside a durable store instead.

Choose the role before the product

A cache alongside DynamoDB can shorten reads and absorb concentrated traffic while preserving DynamoDB as the source of truth. A cache in place of DynamoDB is a different architecture: the application must tolerate the complete loss or regeneration of that state.

Make that durability decision first. Then model the workload, hit rate, object size, request distribution, and current service prices. If augmentation fits, start with the database-caching pattern in the Momento documentation.