DynamoDB Limits: Item Size, API Limits and Quotas

Written by Rafal Wilinski
Last updated: October 23rd, 2026
DynamoDB's maximum item size is 400 KB, including attribute names and values. Query and Scan evaluate at most 1 MB per page, batch writes accept 25 operations, and transactions cover at most 100 distinct items and 4 MB. These fixed constraints are separate from adjustable defaults such as 20 GSIs per table and 40,000 read or write units per second per table or GSI.
The tables below cover items, keys, indexes, operations, throughput, control-plane requests, Streams, backups and vector search. Values are checked against the AWS service quotas and constraints documentation. DynamoDB uses binary size units: 1 KB is 1,024 bytes, so 400 KB is 409,600 bytes.
Fixed limits versus adjustable quotas
A fixed constraint requires a data-model or application change. AWS cannot raise the item-size limit or make a transaction contain more items. An adjustable quota is an account setting: check the applied value for the correct Region in Service Quotas before treating the published default as your ceiling.
In the tables, Service Quotas identifies quotas you can request there. AWS Support identifies increases or allowlisting routed through support. Fixed means design around the value. Where AWS publishes a default without documenting self-service adjustment, the table says so rather than promising an increase.
Items and attributes
| Constraint | Limit or rule | Adjustable? |
|---|---|---|
| Maximum item or record size | 400 KB, including attribute names and values | Fixed |
| String and Binary attribute size | Must fit within the item's 400 KB total | Fixed |
| Attributes per item | No separate count limit; the entire item must fit | Fixed size constraint |
| List, Map or Set elements | No separate count limit; the entire item must fit | Fixed size constraint |
| Nested document depth | 32 levels | Fixed |
| Number precision | 38 significant digits | Fixed |
| Positive Number range | 1E-130 through 9.9999999999999999999999999999999999999E+125 | Fixed |
| Negative Number range | -9.9999999999999999999999999999999999999E+125 through -1E-130; zero is also valid | Fixed |
| General attribute name size | At least one character and less than 64 KB; use 65,535 bytes as the upper bound | Fixed |
| Key attribute names | 1 to 255 characters in the key-schema APIs; index key names must also fit 255 UTF-8 bytes | Fixed |
| User-specified projected attribute names | NonKeyAttributes accepts names up to 255 characters; keep names within 255 UTF-8 bytes | Fixed |
| Empty values | Empty Strings and Binary values allowed outside table/index keys; empty Lists and Maps allowed | Fixed rules |
| Sets | Nonempty, unique elements of one type: String, Number or Binary; no order guarantee | Fixed rules |
| Item with local secondary indexes | Base item plus its corresponding LSI entries must fit the documented 400 KB combined limit | Fixed |
An empty set is invalid even though an empty list is valid. Empty String and Binary elements can appear inside sets, lists and maps. NULL is a supported attribute type; it is different from an absent attribute and cannot be a key.
How DynamoDB counts item size
Count the UTF-8 bytes of every attribute name, plus its value's stored representation. Multibyte characters can use more space than their character count suggests. Binary data is counted using its decoded length, although its base64 wire representation is larger. Numbers use DynamoDB's numeric representation, not simply the length of their JSON text.
Lists and maps add 3 bytes of container overhead and 1 byte per element, in addition to names and nested values. Booleans and nulls use 1 byte plus the attribute name. AWS's item-size calculation rules distinguish this item data from the additional storage overhead used for billing. Do not use the length of JSON.stringify(item) as an exact size validator.
Use the item size and capacity calculator when choosing how much data to keep together. Size also affects cost: writes round up in 1 KB units, and reads in 4 KB units. The 400 KB limit is a maximum, not a recommended item size.
Partition keys and sort keys
| Constraint | Limit or rule | Adjustable? |
|---|---|---|
| String/Binary partition-key value | 1 to 2,048 bytes | Fixed |
| String/Binary sort-key value | 1 to 1,024 bytes | Fixed |
| Key attribute types | String, Number or Binary; no Map, List, Set, Boolean or Null keys | Fixed |
| Base-table primary key | One partition-key attribute, with one optional sort-key attribute | Fixed |
| Multi-attribute GSI keys | Up to 4 partition-key and 4 sort-key attributes | Fixed |
| Distinct partition-key values | No practical count limit | No count quota |
| Distinct sort-key values under a partition key | No practical count limit, subject to item-collection constraints with LSIs | No count quota |
The key-length limits concern values, not the length of attribute names. Number keys follow the Number range and precision rules. For multi-attribute GSIs, use the documented composite-key constraints rather than assuming the base-table key layout applies unchanged.
Table and index quotas
| Resource or operation | Default or limit | Adjustable? |
|---|---|---|
| Tables per account per Region | 2,500 | Service Quotas/account team; documented maximum 10,000 per account per Region |
| Total table size and item count | No practical limit | No size/count quota |
| Global secondary indexes per table | 20 | Service Quotas |
| Local secondary indexes per table | 5 | Fixed |
Explicit INCLUDE attributes across all indexes | 100 total; the same name in two indexes counts twice | Fixed |
NonKeyAttributes per index projection | 20 | Fixed |
| LSI item collection | 10 GB for all base-table items and projected LSI entries sharing a partition-key value | Fixed |
Adding GSIs with UpdateTable | One new GSI per operation | Fixed operation constraint |
| Creating tables with secondary indexes | Serialize creation; AWS documentation conflicts on concurrent indexed-table counts | See note below |
| Table and secondary-index names | 3 to 255 characters: letters, digits, underscore, hyphen or dot | Fixed |
| Table name uniqueness | Within an account and Region | Fixed |
| Index name uniqueness | Within its base table | Fixed |
The 100-attribute projection quota does not apply to ALL or KEYS_ONLY. Automatic projection of table and index keys does not use the user-specified projection allowance. The separate per-index limit comes from the Projection API.
LSIs must be created with the table and cannot later be added or removed. GSIs can be added later, but a new index is not queryable until it becomes ACTIVE. Follow the online index creation rules, and serialize table creation where secondary indexes are included. The CreateTable introduction says only one indexed table can be in CREATING, while its error description mentions up to 250 concurrent indexed-table creations. Because those statements conflict, do not rely on either as an unconditional current quota.
Is DynamoDB limited to 10 GB?
No. The 10 GB item-collection limit applies to tables with LSIs, not to the whole table. It includes the base-table data and LSI projections for one partition-key value. Without LSIs, an item collection can be split across physical partitions. A partition key that accumulates an unbounded history is therefore a particular risk when you choose an LSI.
Data operations and request sizes
| Operation | Limit | Application behavior |
|---|---|---|
GetItem, PutItem, UpdateItem, DeleteItem | One item per call; stored item maximum 400 KB | An update must also leave a valid-sized item |
Query | Up to 1 MB evaluated per call, before filtering | Continue with LastEvaluatedKey |
Scan | Up to 1 MB evaluated per call, before filtering | Continue with LastEvaluatedKey |
Parallel Scan | TotalSegments from 1 to 1,000,000 | Keep each segment's continuation key with that segment |
BatchGetItem | Up to 100 items and 16 MB returned; may return partial results above 1 MB per partition | Retry UnprocessedKeys |
BatchWriteItem | Up to 25 puts/deletes and 16 MB request payload | Retry UnprocessedItems |
TransactWriteItems | Up to 100 distinct items and 4 MB aggregate item data | All actions succeed or fail together |
TransactGetItems | Up to 100 distinct items and 4 MB aggregate item data | Atomic read, without index access |
PartiQL ExecuteStatement | Statement length up to 8,192 characters; reads evaluate up to 1 MB or Limit items | Follow returned NextToken |
PartiQL BatchExecuteStatement | Up to 25 statements | All reads or all writes; check individual errors |
PartiQL ExecuteTransaction | Up to 100 statements, within transaction item and size limits | Reads or writes, not a mixed transaction |
The BatchGetItem API can return a successful response with unprocessed keys. Likewise, BatchWriteItem can return unprocessed operations. Retry only those entries with exponential backoff and jitter. Batches are not transactions, and batch writes do not support updates or per-item conditions.
The wire payload can exceed stored item size because of DynamoDB JSON type wrappers and base64 encoding. A batch must satisfy both the item-level constraints and the total request limit.
A TransactWriteItems idempotency token remains valid for 10 minutes after the first request completes. Reusing it with different request parameters during that window fails; after the window, the request is treated as new.
Transactions cannot contain two actions on the same item, including a ConditionCheck plus an Update. Attach the condition to the update instead. They must stay within one account and Region. An MREC global table does not replicate a transaction atomically to other Regions, and MRSC global tables do not support transactions. See the transaction guide for patterns that preserve the required atomic boundary.
PartiQL is another API surface over the same database constraints. Its statement, batch and transaction limits do not make SQL-style joins or arbitrary cross-item updates available.
Expression limits
| Expression component | Limit | Adjustable? |
|---|---|---|
| Each expression string | 4 KB | Fixed |
Single substitution token such as #name or :value | 255 bytes | Fixed |
Combined ExpressionAttributeNames and ExpressionAttributeValues substitutions | 2 MB | Fixed |
| Operators/functions in an expression | 300 | Fixed |
Operands in an IN comparison | 100 | Fixed |
| Document-path dereferences | 32 | Fixed |
The 255-byte substitution-token limit does not mean every String value stored through an expression is limited to 255 bytes. Account for the combined substitution size separately.
The 300-operator limit applies to condition, filter and update expressions. Comparators, logical keywords, functions and arithmetic operators count. In SET price = price + :delta, the + counts; the assignment = does not. Reserved attribute names remain usable through ExpressionAttributeNames aliases.
Throughput and partition limits
| Scope | Provisioned mode | On-demand mode | Adjustable? |
|---|---|---|---|
| Physical partition | 3,000 read units/s and 1,000 write units/s | Same | Fixed partition capability |
| Table or individual GSI | 40,000 RCU and 40,000 WCU | 40,000 RRU/s and 40,000 WRU/s | Service Quotas |
| Account, per Region | 80,000 RCU and 80,000 WCU across provisioned tables and GSIs | No account-level aggregate read/write quota | Service Quotas for provisioned quotas |
| Minimum provisioned table/GSI capacity | 1 RCU and 1 WCU | Not applicable | Published minimum |
| Provisioned table with Streams enabled | Default 40,000 WCU write quota | Not applicable | Service Quotas |
| Switch from provisioned to on-demand | Up to 4 times per rolling 24 hours | Destination mode | Fixed switching rule |
| Switch from on-demand to provisioned | Destination mode | At any time | Subject to table operation state |
| Provisioned decreases | Up to 27 per UTC day for each table/GSI | Not applicable | Service Quotas |
Units are not interchangeable with request counts. A strongly consistent read of up to 4 KB uses one read unit, an eventually consistent read uses half, and a transactional read uses two. A write of up to 1 KB uses one write unit, or two for a transaction.
The decrease quota starts with four available decreases at the beginning of the UTC day. One replenishes each hour, with at most four available at once. This allows 27 decreases across a full day. Tables and GSIs have independent allowances, but an update decreasing both fails if either has exhausted its allowance.
An on-demand table can also have a user-configured maximum throughput target. That is separate from its service quota and warm throughput, which describes throughput it can handle immediately. Increasing a quota does not fix a hot key or automatically pre-warm a table. Inspect the resource ARN and ThrottlingReasons before changing capacity; the throttling guide explains each limit category.
Control-plane API quotas
These APIs create or describe resources. Their quotas are independent of item read/write capacity and generally apply per account per Region. The AWS constraints page does not mark every API rate as adjustable through Service Quotas, so do not assume a throughput quota increase raises them.
| API or group | Published rate or concurrency constraint |
|---|---|
CreateTable, UpdateTable, DeleteTable, PutResourcePolicy, DeleteResourcePolicy | Default 500 combined operations in flight, adjustable through Service Quotas; separate operation-specific limits still apply |
| Mutable control-plane group above | 2,500 requests/s combined, with lower individual policy limits |
DescribeTable, ListTables, GetResourcePolicy | 2,500 requests/s combined |
PutResourcePolicy | 25 requests/s; wait 15 seconds after a successful policy update before another on that table |
DeleteResourcePolicy | 50 requests/s; blocked for 15 seconds following a successful policy put on that table |
GetResourcePolicy | 100 requests/s |
| Resource-policy document | 20 KB, including whitespace |
DescribeLimits | Call at most once per minute to avoid throttling |
DescribeStream | 10 requests/s |
DescribeTableReplicaAutoScaling, UpdateTableReplicaAutoScaling | 10 requests/s each |
DescribeContributorInsights, ListContributorInsights, UpdateContributorInsights | 5 requests/s each |
DescribeTimeToLive | 10 read request units/s |
UpdateTimeToLive | One enable/disable request per table per hour |
CreateBackup | 50 requests/s |
DescribeBackup, DeleteBackup | 10 requests/s each |
ListBackups | 5 requests/s |
RestoreTableFromBackup, DescribeContinuousBackups | 10 requests/s each |
Change ApproximateCreationDateTimePrecision with UpdateKinesisStreamingDestination | 3 times per 24 hours |
A resource policy adds weight to mutable request accounting: two extra requests per KB of policy. For example, creating a table with a 5 KB policy counts as 11 requests. Deployment tooling should use bounded concurrency and backoff rather than retrying every resource at once. Backup API rates are documented in CreateBackup, DescribeBackup, DeleteBackup and ListBackups.
Streams, backups, PITR, TTL and bulk transfer
| Feature | Limit or constraint | Adjustment or alternative |
|---|---|---|
| DynamoDB Streams retention | 24 hours | Fixed; archive events for longer retention |
Streams GetRecords | Up to 1 MB or 1,000 records per call; shard iterator expires after 15 minutes | Fixed API constraints |
| Simultaneous Streams readers | Design for up to 2 per shard; 1 recommended for global tables | Fan out downstream |
| Point-in-time recovery | Configurable 1 to 35 days; default 35; restore to a new table | Fixed recovery range |
| Latest PITR restore point | Typically about 5 minutes behind current time | Timing, not an immediate rollback guarantee |
| DynamoDB native restores | Up to 50 concurrent restores totaling 50 TB | Published quota |
| AWS Backup restores | Up to 50 concurrent restores totaling 25 TB | Separate AWS Backup quota |
| S3 import jobs | 50 concurrent | Published quota |
| Concurrent import source size | 15 TB in us-east-1, us-west-2 and eu-west-1; 1 TB elsewhere | Region-dependent quota |
| S3 objects per import | 50,000 | Published quota |
| Import destination | New table only; no LSIs | Cannot import into an existing table with this service |
| Full exports | 300 concurrent tasks and 100 TB total in flight | Both quotas are checked |
| Incremental exports | 300 concurrent jobs and 100 TB total in flight | Both adjustable through Service Quotas |
| Incremental export window | 15 minutes to 24 hours, inside the PITR window | Fixed window range |
| TTL attribute | Number containing Unix epoch seconds | Fixed format |
| TTL age and deletion timing | Values more than 5 years in the past are ignored; eligible items are typically deleted within a few days | No immediate deletion deadline |
Exports require PITR and do not consume table read capacity. Imports do not consume write capacity. These operations have their own charges and concurrency quotas, so moving work away from the data plane does not make it quota-free.
TTL is asynchronous cleanup. Expired items can remain in reads and storage until deletion; filter them in the application when expiration affects correctness. The TTL guide includes the epoch conversion and setup details.
Global tables also have separate defaults: 400 MRSC global tables, 40,000 read/write units per second per table for either consistency mode, and 10 TB of new-replica backfill per destination Region per account per day. Coordinate increases across replica Regions through Service Quotas or AWS Support. A local table quota increase alone may not satisfy global-table replica creation requirements.
Vector index quotas
Native vector indexes are available on on-demand tables. Their limits are separate from GSI counts and ordinary read/write units. AWS lists the following in its service quotas page:
| Vector index constraint | Default or maximum | Adjustable? |
|---|---|---|
| Vector indexes per table | 5 | AWS Support |
| Dimensions per vector index | 4,096 | Fixed |
TopK per SearchVectors request | 100 | Fixed |
| Partition-key attributes per vector index | 1 | Fixed |
| Search rate per partition-key value | 1 GB/s | AWS Support |
| Index write rate per partition-key value | 10 MB/s | AWS Support |
| Inline filters per vector index | 18 | Fixed |
| Base-table size for index creation without allowlisting | 600 GB | AWS Support |
| Concurrent vector index creations/deletions per table | 1 | Fixed |
The byte-throughput limits describe data processed, not a fixed number of search requests. Vector dimensions, projected data and the amount examined per search affect throughput. Do not interpret TopK=100 as allowing only 100 vectors in the index.
Workarounds for the limits people hit most
Items larger than 400 KB
Store large binary objects or documents in S3 and keep their object key, metadata and version in DynamoDB. Alternatively, split a document into separately addressable items, or compress a payload that does not need attribute-level querying. Leave space for keys and future attributes. Compression removes the ability to filter the compressed content directly, and splitting creates a multi-item consistency problem you must handle explicitly.
Query or Scan results larger than 1 MB
Keep requesting pages using the returned LastEvaluatedKey as ExclusiveStartKey. A filter runs after DynamoDB evaluates a page, so an empty Items array is not an end-of-results signal. Continue until there is no continuation key. The pagination guide covers the implementation.
An API Limit counts evaluated items, not matches after filtering. If most evaluated data is discarded, fix the key condition or index rather than issuing larger scans. DynamoDB does not provide SQL joins, arbitrary ordering or offset pagination; its query shape follows the key design.
Transactions larger than 100 items or 4 MB
First reduce the atomic unit: keep the small set of records that must change together in one transaction. Move large immutable payloads elsewhere. If a workflow must span several transactions, use explicit progress records, idempotency and compensating actions. Splitting a transaction into batches does not preserve all-or-nothing behavior.
Hot partitions despite spare table capacity
Find the hot key and determine whether reads or writes are throttling. Cache repeated reads when staleness is acceptable, distribute writes across a suitable key space, or shard a write-heavy aggregate and combine results on read. Adaptive capacity and splitting help distribute load, but a single hot item still has a partition's limits. An LSI also prevents splitting an item collection across partitions.
Frequently Asked Questions
What is the DynamoDB item size limit?
Can I increase DynamoDB's maximum record size?
What is the maximum DynamoDB table size?
Does a filter avoid the 1 MB query limit?
How many attributes can a DynamoDB item have?
Which DynamoDB limitations can I increase?
Dynobase is a Professional GUI Client for DynamoDB
Start your 7-day free trial today
Product Features
DynamoDB Tools
- SSH GUI Client
- Chat With Cloud
- MongoDB GUI Client
- AWS Cost Monitoring
- DynamoDB Query Builder
- DynamoDB Code Examples
- DynamoDB Node.js Queries
- DynamoDB JSON Converter
- DynamoDB UUID Generator
- DynamoDB Local Admin GUI
- DynamoDB Pricing Calculator
- DynamoDB Single-Table Design
- Best DynamoDB GUI Clients
- Dynobase vs DynoTable