specification: API Commons Rate Limits specificationVersion: '0.1' schema: https://raw.githubusercontent.com/api-evangelist/interface-research/main/schema/api-commons.yml#/$defs/RateLimits provider: Amazon DynamoDB providerId: amazon-dynamodb created: '2026-05-04' modified: '2026-09-18' generated: '2026-09-18' method: searched source: >- https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ServiceQuotas.html and https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Programming.Errors.html (read 2026-09-18), plus a live unauthenticated POST to https://dynamodb.us-east-1.amazonaws.com/ (X-Amz-Target DynamoDB_20120810.ListTables) to observe the real response headers. note: >- THIS FILE REPLACES A FABRICATION. Until 2026-09-18 it claimed X-RateLimit-Limit / X-RateLimit-Remaining / X-RateLimit-Reset / RateLimit-Policy headers, a 429 status and 10-requests-per-minute tiers. DynamoDB returns none of that. A live probe returns HTTP 400 with an application/x-amz-json-1.0 body {"__type":"...#Exception","message":"..."} and an x-amzn-RequestId header; there is no Retry-After and no RateLimit header family. Throttling is expressed as a typed 400 error, and the limit itself is capacity the caller configures per table rather than a call quota the vendor sets per key. headers: limit: null remaining: null reset: null retryAfter: null policy: null request_id: x-amzn-RequestId error_type: __type (JSON body field; some SDK paths also read x-amzn-ErrorType) note: >- Probed live on 2026-09-18: no rate-limit header of any family is returned. An agent cannot read remaining budget from a response; it must either track consumed capacity itself (ReturnConsumedCapacity on the request) or watch CloudWatch metrics. responseCodes: throttled: 400 quotaExceeded: 400 serviceUnavailable: 500 note: >- ProvisionedThroughputExceededException, ThrottlingException, RequestLimitExceeded and LimitExceededException are all HTTP 400 client errors in the awsJson1_0 protocol, distinguished only by the __type field. InternalServerError is the 5xx case. There is no 429 anywhere in the first-party Smithy model (smithy/dynamodb-2012-08-10.json). consumed_capacity_signal: request_parameter: ReturnConsumedCapacity values: [INDEXES, TOTAL, NONE] response_field: ConsumedCapacity note: >- This is the closest thing DynamoDB has to a rate-limit header, and it is opt-in per request rather than returned by default. It reports what the call just cost in capacity units, not what remains. limits: - name: Per-table throughput, on-demand mode scope: per-table metric: request_units_per_second limit: 40000 burst: null timeFrame: second adjustable: true note: 40,000 read request units and 40,000 write request units per second per table (initial default, raisable via Service Quotas). applies: - Amazon DynamoDB API - name: Per-table throughput, provisioned mode scope: per-table metric: capacity_units_per_second limit: 40000 timeFrame: second adjustable: true note: 40,000 RCU and 40,000 WCU per second for any table or any of its global secondary indexes. applies: - Amazon DynamoDB API - name: Per-account provisioned throughput scope: per-account-per-region metric: capacity_units_per_second limit: 80000 timeFrame: second adjustable: true note: >- 80,000 RCU and 80,000 WCU per second summed across every table and GSI in a Region. Applies to provisioned mode only; on-demand tables carry no account-level throughput quota. applies: - Amazon DynamoDB API - name: Provisioned capacity decreases per table per day scope: per-table metric: update_table_decreases limit: 27 timeFrame: day adjustable: false note: >- 4 decreases available at the start of each UTC day, 1 more per hour up to a ceiling of 4 available at once, totalling 27 across a full day. This is a control-plane rate limit an agent can hit while tuning capacity, and it is enforced per table and per GSI independently. applies: - Amazon DynamoDB Tables API - name: Tables per account per Region scope: per-account-per-region metric: tables limit: 2500 adjustable: true note: Raisable to 10,000 through the account team; beyond that AWS recommends multiple accounts. applies: - Amazon DynamoDB Tables API - name: Simultaneous readers per DynamoDB Streams shard scope: per-shard metric: concurrent_readers limit: 2 adjustable: false note: >- Up to two simultaneous processes per shard for single-Region tables; AWS recommends one for global tables. Exceeding it throttles GetRecords. applies: - Amazon DynamoDB Streams API - name: Active reserved capacity per account scope: per-account metric: provisioned_capacity_units limit: 1000000 adjustable: true applies: - Amazon DynamoDB API - name: Backfilled data for new global-table replicas scope: per-account-per-region metric: terabytes limit: 10 timeFrame: day adjustable: false applies: - Amazon DynamoDB Tables API throttling_reasons: documented: true field: ThrottlingReason format: ResourceType + OperationType + LimitType examples: - TableReadProvisionedThroughputExceeded - TableWriteAccountLimitExceeded - IndexReadAccountLimitExceeded - IndexWriteMaxOnDemandThroughputExceeded - TableReadKeyRangeThroughputExceeded docs: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/throttling-diagnosing-workflow.html note: >- This is unusually good for an agent: the throttle error names the resource, the operation class and which limit was hit, so a caller can tell an account-quota throttle from a hot-partition throttle without guessing. retry_guidance: strategy: exponential backoff with jitter retryable_errors: - ProvisionedThroughputExceededException - ThrottlingException - RequestLimitExceeded - ReplicatedWriteConflictException - InternalServerError non_retryable_without_change: - ValidationException - ConditionalCheckFailedException - ResourceNotFoundException docs: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Programming.Errors.html#Programming.Errors.RetryAndBackoff note: >- AWS's published guidance is 50 ms before the first retry, 100 ms before the second, 200 ms before the third, and to stop retrying at roughly one minute. Batch operations are a special case - BatchGetItem/BatchWriteItem return UnprocessedKeys/UnprocessedItems with HTTP 200 and must be re-driven by the caller rather than retried wholesale. partial_failure: operations: [BatchGetItem, BatchWriteItem] fields: [UnprocessedKeys, UnprocessedItems] status: 200 note: >- A 200 does not mean the whole batch succeeded. This is the single most common way an agent silently loses writes against DynamoDB. maintainers: - FN: Kin Lane email: kin@apievangelist.com url: https://apievangelist.com