DynamoDB and Amazon S3 solve different problems, so the honest answer to "which one" is usually both. DynamoDB is a key-value and document database for structured records you look up, query and update by key. Amazon S3 is object storage for files and blobs — images, backups, logs, videos — that you store and retrieve whole. They are complementary, not either/or.
Should I use DynamoDB or S3?
Use DynamoDB when you have many small structured records you query, filter and update by key with single-digit-millisecond latency. Use Amazon S3 when you store and serve whole files or blobs — images, backups, exports — and retrieve them by name. They are complementary: a very common pattern stores the object in S3 and its metadata in DynamoDB.
DynamoDB vs Amazon S3 at a glance
| Characteristic | DynamoDB | Amazon S3 |
|---|---|---|
| Primary purpose | NoSQL key-value / document database for structured records | Object storage for files, blobs and unstructured data |
| Data unit | Item (a set of typed attributes), addressed by primary key | Object (bytes + metadata), addressed by a key within a bucket |
| Max size per unit | 400 KB per item (attribute names + values) | 5 TB per object (single PUT up to 5 GB; larger uploads use multipart) |
| Query / access |
GetItem, Query, Scan, BatchGetItem, PartiQL, secondary indexes (GSI/LSI) |
GET / PUT / DELETE by key, LIST a bucket; in-place querying via Amazon Athena (or S3 Select for existing customers) |
| Latency profile | Single-digit-millisecond reads/writes for single items at any scale | Durable object throughput; higher per-request latency than a key-value database, not millisecond record lookups |
| Consistency | Eventually consistent by default; strongly consistent reads available per request | Strong read-after-write consistency for all objects and all requests (since 2020) |
| Pricing model | Read/write capacity (RCU/WCU — on-demand or provisioned) + data storage per GB-month | Storage per GB-month (by storage class) + request charges (PUT/GET/LIST) + data retrieval / transfer |
| Best-fit workloads | User profiles, sessions, carts, event/state records, metadata, high-throughput OLTP-style access | Media, backups, data-lake files, static assets, large exports, archival |
Every cell above is drawn from official AWS documentation (see the provenance note at the top of this file).
When to use DynamoDB
Reach for DynamoDB when your data is structured records you access by key:
- Many small items (each under the 400 KB limit) that you read, write and update individually.
- Predictable, low-latency lookups — DynamoDB targets single-digit-millisecond reads and writes for single items at any scale.
- Access patterns you can express with a primary key and secondary indexes: get-by-id, query-a-partition, filter-within-a-partition.
- High write throughput with fine-grained updates (change one attribute without rewriting the whole record).
If you find yourself trying to store a 5 MB file inside an item, that is the signal you have reached DynamoDB's boundary — see DynamoDB item size limit.
When to use S3
Reach for Amazon S3 when your data is a whole file or blob you retrieve by name:
- Images, PDFs, videos, audio, and other binary assets.
- Backups, database exports, and data-lake files (Parquet, CSV, JSON) queried later with a tool like Amazon Athena.
- Large objects — S3 stores objects up to 5 TB each, far beyond any single database record.
- Static website assets and content served directly to users.
S3 is not a database: you cannot query the contents of arbitrary objects with rich indexes the way you query DynamoDB items. In-place SQL-style filtering over an object is available through Amazon Athena (S3 Select remains available to existing customers but was closed to new customers in 2024).
Using them together
The two services are most powerful combined. AWS's own guidance for data too large for a DynamoDB item is to store the object in S3 and keep a pointer in DynamoDB:
- Store the large file (image, document, video) as an object in S3.
- Store its metadata — the S3 object key, content type, owner, tags, timestamps — as an item in DynamoDB, where it is cheaply queryable.
- Look the record up in DynamoDB by key, then fetch the object from S3 using the stored identifier.
One caveat AWS calls out: there are no transactions spanning DynamoDB and S3, so your application handles partial failures (for example, cleaning up an orphaned S3 object if the DynamoDB write fails).
What an S3 object becomes in DynamoDB
Take a 12 MB PDF. In S3 it is one object, and you can read a slice of it without
touching the rest:
aws s3api put-object --bucket media-prod \
--key uploads/2026/07/report-8231.pdf --body report.pdf
aws s3api get-object --bucket media-prod \
--key uploads/2026/07/report-8231.pdf \
--range bytes=0-1048575 first-mb.pdf
That byte-range fetch is the operation DynamoDB has no version of. An item is
read whole. ProjectionExpression trims what crosses the wire, but AWS computes
capacity on item size rather than response size, and says consumption is "the
same whether you request all of the attributes ... or just some of them".
That rule is what people get wrong when they try to keep a blob inside the item.
A 380 KB item sits legally under the 400 KB ceiling, and every read of it costs
95 read capacity units strongly consistent, 47.5 eventually consistent. You pay
that even when all you wanted was a 20-byte status attribute.
The 12 MB PDF does not fit under any encoding: 400 KB covers attribute names and
values together, and a binary attribute is charged its raw byte length. So the
split AWS recommends follows directly from the read-unit rule.
{
"TableName": "documents",
"Item": {
"PK": {"S": "DOC#8231"},
"SK": {"S": "V#3"},
"s3Bucket": {"S": "media-prod"},
"s3Key": {"S": "uploads/2026/07/report-8231.pdf"},
"contentType": {"S": "application/pdf"},
"bytes": {"N": "12582912"},
"sha256": {"S": "9f2c1e7a"},
"ownerId": {"S": "USER#41"},
"createdAt": {"N": "1785283200"}
}
}
That item is a few hundred bytes, so every metadata read costs the minimum read
unit and stays there permanently, because the bytes it describes live elsewhere.
What you take on is the bookkeeping S3 was doing. V#3 in the sort key is you
implementing versioning that S3 offers as a bucket setting. bytes and sha256
are you recording facts S3 already knows about its own object. Both can drift
from the object they describe, and neither service will tell you when they have.
Working with DynamoDB
Once you have chosen DynamoDB for the structured half of your data, DynoTable is a desktop DynamoDB client for browsing, editing and querying tables across macOS, Windows and Linux. It reads your standard AWS credential chain, so there is nothing DynamoDB-specific to migrate — point it at your region and tables and your data stays in DynamoDB.
When you need to hand-build the GetItem, Query, Update or condition expressions that back the metadata-in-DynamoDB pattern above, the free DynamoDB Expression Builder generates the request in the AWS SDK, CLI and boto3 forms. To size an item against the 400 KB limit before you decide what belongs in S3, the item size calculator measures a record's byte size.
FAQ
Can DynamoDB store files or images?
Small ones, within limits. A DynamoDB item can hold binary data, but the entire item — every attribute name and value — must stay under 400 KB. For anything larger, AWS's documented best practice is to store the file as an object in Amazon S3 and keep the S3 object key (plus metadata) in a DynamoDB item.
Is S3 cheaper than DynamoDB?
They price differently, so it depends on the workload rather than a flat answer. S3 charges for storage per GB-month plus per-request and retrieval fees, and is generally the cheaper home for large volumes of infrequently accessed bytes. DynamoDB charges for read/write capacity plus storage and is built for high-throughput, low-latency access to many small records. Storing large blobs in DynamoDB is both size-limited and comparatively expensive — which is why the S3-object-plus-DynamoDB-metadata split is the standard pattern.
DynamoDB or S3 for JSON?
If the JSON is a structured record you query and update by key — a user, an order, a session — DynamoDB fits, and it maps JSON to typed attributes and supports PartiQL. If the JSON is a whole document or data-lake file you store and later scan in bulk (for example querying it with Amazon Athena), S3 fits. A frequent hybrid keeps the queryable fields in DynamoDB and the full JSON payload as an object in S3.
Related
- Learn: DynamoDB item size limit · When to use DynamoDB
- Build requests visually with the DynamoDB Expression Builder.
- Size records with the DynamoDB item size calculator.
- Download DynoTable to work with your DynamoDB tables.
References
- Best practices for storing large items and attributes — AWS DynamoDB Developer Guide
- DynamoDB service quotas (400 KB item size limit)
- DynamoDB read consistency
- What is Amazon S3? (durability and consistency model)
- Uploading objects to Amazon S3 (5 GB single PUT)
- Amazon S3 multipart upload limits (5 TB maximum object size)
- Amazon S3 pricing
Last verified 2026-07-13 against official AWS DynamoDB and Amazon S3 documentation. Amazon S3, DynamoDB and Athena are services of Amazon Web Services, referenced here for identification only.
Top comments (0)