Short answer
DynamoDB Streams pricing is $0.02 per 100,000 GetRecords calls for custom (non-Lambda) consumers, and the first 2.5 million reads each month are free per account per Region. Lambda consumers pay nothing for those reads unless they run on Lambda Managed Instances.Enabling Streams is free; you are billed only when something reads the stream, and records live for 24 hours. For most workloads the read charge is small next to table capacity, which makes capacity, not Streams, the cost lever worth chasing.
What DynamoDB Streams pricing includes
Streams cost has two independent layers. The first is the read charge you pay to pull records with the GetRecords API. The second applies only if you route changes to Kinesis Data Streams for change data capture (CDC), which adds a separate per-write fee on top of Kinesis infrastructure.According to the AWS DynamoDB pricing page, each GetRecords call is billed as one Streams read request unit and returns up to 1 MB of data or 1,000 records, whichever limit is hit first. Reads from Streams are metered separately from your table’s read capacity, so they never touch your RCUs.
| Component | Rate (US East) | Free tier | Notes |
|---|---|---|---|
| Streams read, non-Lambda | $0.02 / 100,000 | 2.5M reads/month/Region | Up to 1 MB or 1,000 records per call |
| Streams read, Lambda | $0.00 | Unlimited | Exception: Lambda Managed Instances billed at standard rates |
| Streams read, Global Tables replication | $0.00 | Unlimited | Internal replication reads are not charged |
| Streams enabled but unread | $0.00 | N/A | No idle cost |
| Kinesis CDC units (optional) | $0.10 / million | None | One CDC unit for each write of up to 1 KB captured to Kinesis, plus Kinesis charges |
What actually drives your Streams read cost
Each item modification that changes data creates a stream record, but your bill is not a function of writes. It is a function of how often your consumers call GetRecords, which depends on active shard count, polling frequency, and how full each batch is. A quiet table read by a busy poller can cost more than a busy table read efficiently. Use this to estimate a custom consumer, then treat the result as a planning figure, not a quote.Illustrative calculation (US East, 30-day month, records fit one batch)
| Scenario | Active shards | Polls/sec/shard | Monthly calls | Billable | Cost | Standard Lambda |
|---|---|---|---|---|---|---|
| Light | 1 | 1 | 2.59M | 0.09M | $0.02 | $0.00 reads |
| Moderate | 4 | 1 | 10.37M | 7.87M | $1.57 | $0.00 reads |
| Busy | 10 | 2 | 51.84M | 49.34M | $9.87 | $0.00 reads |
| Aggressive | 20 | 5 | 259.2M | 256.7M | $51.34 | $0.00 reads |
Why Lambda can eliminate Streams read charges
AWS does not charge for GetRecords calls made by standard Lambda functions triggered from a DynamoDB stream, which removes the $0.02 per 100,000 Streams-read fee. You still pay for Lambda requests and duration, while custom consumers incur both their own compute costs and billable Streams reads after the free tier. Compare total cost using your batch size, runtime, polling behavior, and throughput.
Watch out: the Lambda Managed Instances exception. Per the AWS pricing page, GetRecords calls from DynamoDB triggers are free unless the function runs on Lambda Managed Instances, which are billed at standard Streams rates ($0.02 per 100,000). If you moved a consumer onto Managed Instances, re-check your bill: those reads are no longer free.
Illustrative example (standard Lambda, US East, x86): 100 million records batched 100 per invocation produces 1 million invocations. At 128 MB memory and 50 ms average duration, that is 6,250 GB-seconds, or roughly $0.10 in compute before Lambda free-tier allowances. If the account has unused Lambda free tier, both the one million requests and 6,250 GB-seconds fall within it, making the Lambda charge $0.00; otherwise, the result varies with batch size, memory, duration, and existing free-tier use.
Which consumer should you use
Follow the first condition that matches your workload.
- Need records retained beyond 24 hours? Use Kinesis Data Streams CDC.
- Need more than two consumers reading the same stream at once? Use Kinesis Data Streams CDC.
- Need to fan out to Kinesis Firehose, Data Analytics, or another non-Lambda downstream? Use Kinesis Data Streams CDC.
- Running your function on Lambda Managed Instances? Your reads are billed at standard Streams rates, so compare total cost against Kinesis for your volume.
- Need a custom consumer with precise polling control? Use the DynamoDB Streams Kinesis Adapter version 2.4.x or later with KCL 3.5.x or later and AWS SDK for Java 2.x. AWS lists KCL 1.x and 2.x as outdated, and KCL 1.x reached end of support on January 30, 2026.
- None of the above? Use standard Lambda with event source mapping filters. It is the lowest-overhead path for most architectures.
DynamoDB Streams vs Kinesis for CDC
Both mechanisms capture item-level changes, but they price and behave differently.| Dimension | DynamoDB Streams | Kinesis Data Streams CDC |
|---|---|---|
| DynamoDB charge | $0.02 / 100K reads | $0.10 / million CDC units |
| CDC unit basis | Not applicable | One CDC unit for each write of up to 1 KB captured to Kinesis |
| Infrastructure | None, serverless | Shard-hour or per-GB Kinesis fees apply |
| Lambda reads | Free (standard functions) | Lambda request and duration charges; Kinesis charges may apply |
| Retention | 24 hours | Up to 365 days |
| Consumers | Two per shard recommended | Many, with enhanced fan-out |
How TTL and single-table design inflate cost
Two design choices can increase stream volume. First, when DynamoDB TTL expires an item, DynamoDB writes a system-generated delete record to the stream. For a custom consumer, large TTL expiry volume can raise Streams costs when it increases GetRecords calls or reduces batch utilization; Streams does not charge per record.Second, a single-table design funnels every entity type into one stream, so a consumer that only cares about orders still gets invoked for users and products.
Lambda event source mapping filters can reduce unnecessary function invocations from both, but they do not remove records from the stream. You can filter on eventName, on dynamodb keys and attributes, and on the userIdentity field before invocation.
Per the DynamoDB developer guide, a filter matching userIdentity type Service and principalId dynamodb.amazonaws.com invokes your function only for TTL deletes, which is the clean way to archive them.
To drop all deletes including TTL, filter eventName to INSERT and MODIFY. Excluding only TTL deletes while keeping application deletes is the awkward case: it is easier to check userIdentity in your function logic than to express that exclusion in a filter pattern.
Reduce the costs that actually move your bill
While DynamoDB Streams pricing is set entirely by AWS, you can still cut overall AWS spend by optimizing commitments across eligible services. Usage.ai continuously analyzes AWS usage across your environment to identify commitment opportunities and adjust coverage as workloads evolve.With Flex Insured Commitments, teams can capture the 30% to 50% savings available through AWS commitment programs without taking on the full risk of long-term commitments. If a commitment ever costs more than the equivalent on-demand usage, Cashback Protection covers the difference, subject to terms, so you can keep adapting as your infrastructure changes.
Streams cost-control checklist
Run this before you ship a new stream consumer or during a quarterly audit.- Confirm the consumer type: standard Lambda (free reads), Lambda Managed Instances (billed), custom, or Kinesis CDC.
- If custom, estimate GetRecords calls from active shards and polling frequency, then subtract the 2.5 million free reads per account per Region.
- Right-size batch size and polling before chasing volume; both change the read count directly.
- Add expected TTL deletion volume to your estimate; TTL deletes are system-generated stream records.
- Apply event source mapping filters so the function is not invoked for event types or entity types it does not need.
- Confirm no consumer relies on records older than 24 hours; if it does, plan for Kinesis CDC.
- Confirm no more than two consumers read a single shard concurrently.
- Set a CloudWatch alarm on GetRecords volume so billable reads never drift past your threshold unnoticed.
Streams reads are a rounding error provisioned capacity is where the money is. Flex Commitments capture AWS discounts with conditional cashback on underutilization.
Frequently asked questions
Does DynamoDB Streams consume my table's read capacity?
No. Streams reads are billed in their own Streams read request units, which are entirely separate from the read capacity units your application uses against the table. Enabling and reading a stream does not consume or reduce your table's provisioned or on-demand read capacity.
Do Lambda functions always read Streams for free?
Almost always. Standard serverless Lambda functions triggered off a stream read for free, and Global Tables replication reads are free too. The one exception is a function running on Lambda Managed Instances, which is billed at the standard $0.02 per 100,000 rate. You still pay separately for Lambda requests and duration in every case.
Do TTL deletions generate stream records?
Yes. When TTL expires an item, DynamoDB writes a delete record to the stream if Streams is enabled. It carries a userIdentity field marking it as a service-initiated delete. Streams does not charge per record, but for a custom consumer a high TTL expiry rate can still raise cost by increasing GetRecords calls. You can filter to invoke your function only on those records, or drop all deletes by filtering event type.
How long are Streams records retained, and can I extend it?
Records are retained for 24 hours and then deleted automatically. There is no setting to extend that window. If a consumer falls more than 24 hours behind, it loses records. When you need a longer replay window, route changes to Kinesis Data Streams, which supports retention up to 365 days.
How do I monitor my Streams read volume for cost?
Use the CloudWatch SuccessfulRequestLatency metric with the SampleCount statistic, which reports the number of GetRecords calls per stream. Because it counts free reads (Lambda, Global Tables) alongside billable ones, subtract those to isolate charged reads, then alarm on the result. DynamoDB Streams does not support cost allocation tags, so CloudWatch is the primary native visibility path.