---
title: Amazon DynamoDB Pricing: The On-Demand vs Provisioned Crossover and the GSI Multiplier
description: DynamoDB on-demand bills $1.25 per million writes and $0.25 per million reads — pay-per-request convenience with no capacity planning. Provisioned at $0.00065/WCU-hour wins on steady traffic above ~50% utilization. Every GSI doubles the write cost, IA tier cuts storage 60% but adds 25% to request fees, and Global Tables compound the bill per region.
url: https://www.factualminds.com/blog/amazon-dynamodb-pricing-on-demand-provisioned-gsi-streams/
datePublished: 2026-06-13T00:00:00.000Z
dateModified: 2026-06-13T00:00:00.000Z
author: palaniappan-p
category: Cost Optimization & FinOps
tags: amazon-dynamodb, dynamodb-pricing, aws-pricing, cost-optimization, finops, database
---

# Amazon DynamoDB Pricing: The On-Demand vs Provisioned Crossover and the GSI Multiplier

> DynamoDB on-demand bills $1.25 per million writes and $0.25 per million reads — pay-per-request convenience with no capacity planning. Provisioned at $0.00065/WCU-hour wins on steady traffic above ~50% utilization. Every GSI doubles the write cost, IA tier cuts storage 60% but adds 25% to request fees, and Global Tables compound the bill per region.

import PricingHeroStats from '~/components/blog/PricingHeroStats.astro';
import PricingDimensionTable from '~/components/blog/PricingDimensionTable.astro';
import BillSurpriseCallout from '~/components/blog/BillSurpriseCallout.astro';
import PricingDecisionCard from '~/components/blog/PricingDecisionCard.astro';

Amazon DynamoDB has the most flexible pricing model of any AWS database — on-demand for unpredictable traffic, provisioned for steady throughput, two storage classes, optional PITR, Global Tables for multi-region, DAX for caching, Streams for event-driven downstream. The flexibility is the problem. Every dimension represents a cost decision and the wrong default — on-demand for a steady workload, three GSIs when one would do, Standard storage for cold data, PITR on every table — compounds into a bill multiple times what the workload would cost with thoughtful configuration.

<PricingHeroStats
  stats={[
    { value: '$1.25', label: 'On-demand / M writes', note: '$0.25/M reads; pay-per-request convenience' },
    { value: '$0.00065', label: 'Provisioned WCU-hour', note: 'Wins on steady traffic above ~50% utilization' },
    { value: '~2×', label: 'GSI write multiplier', note: 'Per GSI; multiplicative on every write' },
    { value: '60%', label: 'IA storage saving', note: 'For data accessed under ~3% of the time' },
  ]}
  caption="us-east-1 list prices, June 2026. Verify against the AWS DynamoDB pricing page for your region."
/>

This post is the bill story. For DynamoDB single-table modeling and access pattern design, see our [DynamoDB single-table design patterns guide](/blog/dynamodb-single-table-design-patterns-for-saas/). For the RDS-vs-DynamoDB architectural choice, the [DynamoDB vs RDS comparison](/compare/dynamodb-vs-rds/) covers when each primitive is right.

## The Nine DynamoDB Billing Dimensions

<PricingDimensionTable
  title="DynamoDB pricing breakdown — us-east-1, June 2026"
  intro="Capacity mode, storage class, and replication topology are the dominant decisions. Streams, backup, and DAX are smaller but compound."
  region="us-east-1"
  dimensions={[
    {
      name: 'On-demand writes',
      unitPrice: '$1.25 / million WRU',
      example: '20M writes / month',
      monthly: '$25',
      note: '1 WRU = 1 KB write',
      highlight: true,
    },
    {
      name: 'On-demand reads',
      unitPrice: '$0.25 / million RRU',
      example: '200M strongly-consistent reads',
      monthly: '$50',
      note: '1 RRU = 4 KB strongly-consistent read',
    },
    {
      name: 'Provisioned WCU',
      unitPrice: '$0.00065 / WCU-hour',
      example: '500 WCU steady',
      monthly: '$237',
      note: 'Pay for capacity whether used or not',
      highlight: true,
    },
    {
      name: 'Provisioned RCU',
      unitPrice: '$0.00013 / RCU-hour',
      example: '1000 RCU steady',
      monthly: '$95',
      note: 'Strongly-consistent uses 1 RCU per 4 KB',
    },
    {
      name: 'Standard storage',
      unitPrice: '$0.25 / GB-month',
      example: '500 GB table',
      monthly: '$125',
      note: 'Includes 25 GB free',
    },
    {
      name: 'Standard-IA storage',
      unitPrice: '$0.10 / GB-month',
      example: '500 GB cold-tier table',
      monthly: '$50',
      note: 'Request units cost 25% more',
      highlight: true,
    },
    {
      name: 'PITR continuous backup',
      unitPrice: '$0.20 / GB-month of source data',
      example: '200 GB table',
      monthly: '$40',
      note: '35-day per-second recoverability',
    },
    {
      name: 'On-demand backup',
      unitPrice: '$0.10 / GB-month + $0.15/GB restore',
      example: 'Daily 200 GB snapshots',
      monthly: '~$20 + restores',
      note: 'Half the cost of PITR for snapshot-style backup',
    },
    {
      name: 'DynamoDB Streams reads',
      unitPrice: '$0.02 / 100K reads',
      example: '5M Streams reads / month',
      monthly: '$1',
      note: 'First 100K per account per month free',
    },
    {
      name: 'Global Tables (per replica region)',
      unitPrice: 'Each region: full storage + rWCU writes',
      example: '2-region Global Table',
      monthly: '~2× single-region cost',
      note: 'Plus inter-region transfer for replication',
      highlight: true,
    },
    {
      name: 'DAX (caching layer)',
      unitPrice: 'Per-node-hour by instance type',
      example: '3-node dax.t3.medium cluster',
      monthly: '~$100',
      note: 'Reduces RCU consumption when cache hit rate is high',
    },
  ]}
  footnote="Storage cost includes 25 GB free per month per account. Request costs (WRU/RRU/WCU/RCU) start billing from the first unit."
/>

## The On-Demand vs Provisioned Crossover

The headline DynamoDB cost decision: capacity mode. On-demand is convenient — no capacity planning, no provisioned-throughput-exceeded errors, scales instantly. Provisioned is cheaper at steady utilization but requires sizing decisions and auto-scaling configuration.

The break-even math:

<PricingDimensionTable
  title="On-demand vs provisioned — break-even by utilization"
  intro="Same workload throughput; different capacity mode. Provisioned wins when utilization stays above ~50% sustained."
  region="us-east-1"
  dimensions={[
    {
      name: 'On-demand 100 writes/sec',
      unitPrice: '~260M writes/month',
      example: '100 WPS × 730 hours × 3600s',
      monthly: '~$325/mo',
      note: '$1.25/M baseline',
    },
    {
      name: 'Provisioned 100 WCU (matches on-demand peak)',
      unitPrice: '100 WCU × 730h × $0.00065',
      example: 'Always-on capacity',
      monthly: '~$47/mo',
      note: '85% cheaper at 100% utilization',
      highlight: true,
    },
    {
      name: 'Provisioned 100 WCU at 50% utilization',
      unitPrice: 'Same fixed cost',
      example: 'Wasted half the capacity',
      monthly: '~$47/mo',
      note: 'Still cheaper than on-demand',
    },
    {
      name: 'Provisioned 100 WCU at 25% utilization',
      unitPrice: 'Same fixed cost',
      example: 'Significantly over-provisioned',
      monthly: '~$47/mo',
      note: 'Now equivalent to on-demand at 25M writes',
    },
    {
      name: 'Provisioned 100 WCU at 10% utilization',
      unitPrice: 'Same fixed cost',
      example: 'Bursty / idle workload',
      monthly: '~$47/mo',
      note: 'On-demand at $0.0325/mo (no waste) is cheaper',
    },
  ]}
  footnote="Auto-scaling on provisioned narrows the on-demand gap but lags traffic by minutes. For very bursty traffic, on-demand absorbs spikes provisioned cannot."
/>

The decision tree:

- **Predictable, steady, high-utilization workload**: provisioned with auto-scaling.
- **Variable, bursty, unpredictable workload**: on-demand.
- **New workload with unknown traffic pattern**: start on-demand; switch to provisioned once traffic stabilizes and the steady-state rate is known.
- **Mixed workload (steady base + occasional spikes)**: provisioned for the base + on-demand for spike absorption is not directly supported, but auto-scaling provisioned with conservative max-capacity acts similarly.

## The GSI Multiplier

Every Global Secondary Index that includes the attributes of a write incurs an additional WRU/WCU at the same rate as the base table write. A table with 3 GSIs costs 4× the write capacity per write (base + 3 indexes).

<BillSurpriseCallout
  variant="surprise"
  title="3 GSIs on a write-heavy table quadruples the write cost"
  amount="4× WRU/WCU consumption per write"
>
  Each GSI is a separate write target. A 10M-writes-per-day table with 3 GSIs effectively writes 40M times per day from
  a capacity perspective. Design indexes for high-value query patterns only; use sparse GSIs where most records do not
  need to be queried by the GSI partition key; consider single-table design patterns that combine multiple access
  patterns into one base table with fewer GSIs.
</BillSurpriseCallout>

The mitigations:

1. **Sparse GSIs.** Only records with a non-null value in the GSI partition key are indexed. For predicates that match a small subset of rows, sparse GSIs dramatically reduce the multiplier.
2. **Single-table design.** Group multiple entity types into one table with the same key structure; fewer GSIs serve the same access patterns. See our [single-table design guide](/blog/dynamodb-single-table-design-patterns-for-saas/).
3. **GSI projection.** GSIs can project all attributes, only key attributes, or a subset. Smaller projections cost less in storage; the write capacity is the same regardless.
4. **Eventually consistent reads on GSIs.** GSIs only support eventually consistent reads by default, which cost half the RCU of strongly consistent.

## Standard-IA Storage: Cheap When Cold

DynamoDB Standard-IA storage at $0.10/GB-month is 60% cheaper than Standard at $0.25/GB-month — but read and write request units cost 25% more. The crossover is access frequency: data accessed less than roughly 3% of the time benefits from IA; hotter data costs more on IA than Standard.

The common use cases for IA:

- Audit logs with 7-year retention but rare query.
- Historical session data archived after the session ends.
- Time-series tables with hot/cold partitioning where old partitions are rarely read.
- Tenant-archive tables for inactive customers in B2B SaaS.

The waste pattern: enabling IA on hot tables. The 25% request-unit premium on a high-traffic table exceeds the 60% storage saving when reads/writes dominate the bill.

## Global Tables: Each Region Is Full Cost

Global Tables provide multi-region active-active replication for DynamoDB. The pricing model: each region bills its own storage, read/write capacity, and the replicated writes from other regions (rWCUs at the standard per-WCU rate).

A 2-region Global Table effectively doubles the write cost — every write applies in both regions. Add the inter-region replication data transfer at $0.02/GB and the bill grows further. A 3-region Global Table triples the write cost; a 5-region setup quintuples it.

<BillSurpriseCallout
  variant="trap"
  title="Global Tables enabled for read replication when DAX or read-through cache would do"
  amount="2–5× the single-region cost"
>
  Global Tables are correct when you need multi-region writes — active-active applications, cross-region disaster
  recovery with low RPO. They are overkill when you need only read replication. A single-region table with a DAX cache
  or an application-side read-through cache in the secondary region serves cross-region reads at a fraction of the cost.
  Match the topology to the actual requirement.
</BillSurpriseCallout>

## PITR vs On-Demand Backup

PITR at $0.20/GB-month of source table data is roughly 2× the on-demand backup warm-storage rate ($0.10/GB-month). The premium pays for per-second recoverability over the last 35 days.

The right choice depends on RPO:

- **PITR**: applications requiring per-second recovery (financial transactions, ordered event sourcing).
- **On-demand backup with daily schedule**: most other workloads. The point-in-time precision of 24-hour granularity is acceptable for most operational restore use cases.

Enabling PITR by default on every table is the most common DynamoDB backup waste pattern. Be deliberate about which tables require per-second recovery.

## When to Use Each Capacity / Storage Configuration

<PricingDecisionCard
  headline="On-demand for bursty / new workloads; provisioned for predictable steady traffic; IA for cold data; PITR only when RPO requires per-second precision."
  useWhen={[
    'On-demand: bursty traffic, unpredictable load, new workloads with unknown shape, dev / test environments',
    'Provisioned with auto-scaling: steady production traffic above ~50% utilization, well-understood workload',
    'Reserved Capacity: very predictable, very-high-volume legacy workloads (uncommon for new development)',
    'Standard-IA storage: audit logs, archived sessions, cold partitions of time-series, inactive tenants',
    'PITR: financial transactions, state-machine workflows requiring per-second recovery, regulated workloads',
    'Global Tables: multi-region active-active applications, low-RPO cross-region DR',
    'DAX: read-heavy workloads with high cache-hit potential (top-N queries, hot keys)',
  ]}
  avoidWhen={[
    'On-demand for steady high-utilization workloads — provisioned is dramatically cheaper',
    'GSIs without explicit access-pattern justification — each one multiplies write cost',
    'IA storage on hot tables — the request-unit premium exceeds the storage saving',
    'PITR enabled by default — only enable where per-second recovery is required',
    'Global Tables for read-only multi-region — DAX or app-side cache is cheaper',
    'Reserved Capacity on tables with traffic uncertainty — auto-scaling provisioned is more flexible',
  ]}
  footnote="DynamoDB cost optimization is largely capacity-mode and index-strategy decisions, not run-time tuning. Get them right at design time."
/>

## A 30-Day DynamoDB Bill Cleanup Plan

**Week 1 — Capacity mode audit.** For each table, check the CloudWatch `ConsumedReadCapacityUnits` and `ConsumedWriteCapacityUnits` against the on-demand vs provisioned crossover. Switch over-provisioned-on-demand tables to provisioned, and switch under-utilized-provisioned tables to on-demand (or right-size the provisioned capacity).

**Week 2 — GSI audit.** For each table, list GSIs and verify each one serves a high-value query pattern. Drop unused GSIs. For GSIs with low predicate match rates, evaluate converting to sparse GSIs.

**Week 3 — Storage class evaluation.** Identify tables with cold-tier characteristics (low access frequency, large size, retention-focused). Migrate eligible tables to Standard-IA.

**Week 4 — PITR and Global Tables scope.** Review PITR-enabled tables; disable on tables where daily on-demand backup would suffice. Review Global Tables setup; evaluate whether read-only secondary regions could be served by DAX instead.

## What This Post Doesn't Cover

- **DynamoDB Streams + Lambda design patterns** — covered in our event-driven architecture content.
- **DAX deployment patterns and sizing** — covered in our caching architecture content.
- **Migration from DynamoDB to RDS or vice versa** — covered in the [DynamoDB vs RDS comparison](/compare/dynamodb-vs-rds/).
- **DynamoDB Exports to S3** — useful pattern for analytics; bills at $0.10/GB exported plus standard S3 storage.

## If You Only Do One Thing This Week

Audit your largest table's capacity mode against actual utilization. Run a CloudWatch query for `ConsumedReadCapacityUnits` and `ConsumedWriteCapacityUnits` over the last 30 days, calculate the average and 95th percentile. If you are on on-demand with sustained utilization that would translate to >50% of a provisioned setup, switch to provisioned with auto-scaling — typical savings 50–70% on the request cost. If you are on provisioned with utilization consistently below 30%, switch to on-demand. The change is a single API call (`update-table --billing-mode`) and applies immediately.

For the broader data-modeling decisions that affect cost — single-table design, access patterns, key strategy — the [DynamoDB single-table design patterns guide](/blog/dynamodb-single-table-design-patterns-for-saas/) covers the design side.

## FAQ

### When does provisioned capacity beat on-demand?
The crossover is roughly 50% sustained utilization of the provisioned capacity. On-demand at $1.25/M writes and $0.25/M reads bills exactly what you consume; provisioned at $0.00065/WCU-hour and $0.00013/RCU-hour costs the same whether you use the capacity or not. For workloads with predictable traffic that consistently runs above 50% of the provisioned rate, provisioned is cheaper. For workloads with high peak-to-average ratios (5×+), on-demand wins because the provisioned setup would need to be sized for peak and waste capacity at the median. Auto-scaling on provisioned narrows but does not close the gap because auto-scaling lags traffic by minutes.

### Why does adding a GSI roughly double the write cost?
Every write to a DynamoDB table is also written to every Global Secondary Index that includes the attributes being written, billed at the same WRU/WCU rate as the base table write. A table with 3 GSIs incurs 4× the write capacity (base + 3 indexes) on every write. GSIs are essential for query flexibility but the cost is multiplicative. Design indexes thoughtfully: each GSI should serve a high-value query pattern. Sparse GSIs (only the records that match a predicate are indexed) reduce the multiplier when most rows do not need to be queried by the GSI partition key.

### When is the Standard-IA storage class worth it?
Standard-IA at $0.10/GB-month is 60% cheaper than Standard at $0.25/GB-month for storage, but read and write request units cost 25% more (read $0.000313/RRU-hour-equivalent vs $0.00025, write $0.000813 vs $0.00065). The break-even is access frequency. For data accessed less than ~3% of the time, IA storage savings exceed the request premium. For audit logs, historical records, infrequently-queried session data, and time-series partitions older than a certain age, IA is dramatically cheaper. For hot data, Standard is correct.

### How expensive are Global Tables really?
Each Global Table region bills its own storage, read/write capacity, and the replicated writes from other regions (rWCUs at the same per-WCU rate as primary writes). A two-region Global Table effectively doubles the write cost (each write applies in both regions) plus the inter-region data transfer at $0.02/GB for the replication traffic. For three regions, write costs triple plus more transfer. Global Tables are correct when you need multi-region read locality or active-active writes; for read replicas with single-region writes, a single-region table plus DAX or a read-through cache in the secondary region is often cheaper.

### Should I be using Reserved Capacity for DynamoDB?
Rarely. DynamoDB Reserved Capacity (1-year or 3-year commit on provisioned RCU/WCU) offers ~50–75% discount on the committed capacity. The catch: the commit is per-region per-account and locks you into the chosen capacity for the term. Most workloads with traffic stable enough to justify Reserved Capacity are also stable enough to use auto-scaling on provisioned, which gives similar cost outcomes with more flexibility. Reserved Capacity is a fit for very predictable, very-high-volume workloads where the lock-in is acceptable. Most modern DynamoDB workloads use on-demand or provisioned with auto-scaling; Reserved Capacity is a legacy purchase mechanism.

### How does PITR pricing differ from on-demand backup?
Point-in-Time Recovery (PITR) bills $0.20/GB-month of source table data continuously — you pay for the ability to restore to any second in the last 35 days. On-demand backups bill $0.10/GB-month per snapshot with a $0.15/GB restore fee. For tables that genuinely need per-second recoverability, PITR is operationally simpler. For tables where daily snapshots with point-in-time precision are sufficient, on-demand backups at half the storage rate are cheaper. The right choice depends on the business RPO; do not enable PITR by default on tables where a daily snapshot would meet the recovery requirement.

### What is the cost impact of DynamoDB Streams + Lambda triggers?
DynamoDB Streams reads are billed at $0.02 per 100K reads, but the first 100K read units per month are free per account. For most workloads using Streams to drive Lambda triggers, the Streams read cost is negligible — the bill driver is the Lambda invocation cost downstream. The exception: very high-volume tables (millions of writes per hour) where the Streams reads exceed the free tier and bill at a few cents per million writes. Streams are almost always worth enabling for the operational flexibility (real-time replication, audit trail, downstream event-driven processing).

---

*Source: https://www.factualminds.com/blog/amazon-dynamodb-pricing-on-demand-provisioned-gsi-streams/*
