Can DynamoDB store JSON?
Yes. DynamoDB can store JSON by mapping it to its document types: map (M) for objects and list (L) for arrays, nested up to 32 levels deep. Each item holds up to 400 KB. DynamoDB's type system is a superset of JSON, so any JSON document can be stored as an item and then filtered, updated, and read.
How JSON maps to DynamoDB types
- JSON object → Map (M)
- JSON array → List (L)
- string / number / boolean / null → S / N / BOOL / NULL
Lists and maps can nest up to 32 levels deep, so a full JSON document becomes one item.
The stored size is smaller than the JSON
The type-tagged wire format looks wasteful, and people assume they are billed for it. They are not. DynamoDB charges on the item size, which is the sum of each attribute name plus each value, with none of JSON's quotes, colons, commas or braces.
A nine-attribute order document with a nested address, a two-line item array and a two-element tag list measures three different ways:
| Measurement | Bytes |
|---|---|
| DynamoDB JSON as sent over the wire | 607 |
| The same document as plain minified JSON | 447 |
| Billed item size | 350 |
So the stored item is 22% smaller than the JSON you started with, and 42% smaller than the request that carried it. Numbers do most of the work: 149.97 stores in about 4 bytes against 6 characters of text. Strings and names are counted exactly; AWS documents number encoding as roughly a byte per two significant digits, so read 350 as accurate to a few bytes rather than to one.
What does cost you is naming. Attribute names and map keys account for 148 of those 350 bytes, 42% of the item, and you pay them on every copy. Shortening shippingAddress to addr across a billion items is a real saving. You can size any document in the item size calculator, which we checked against the engine's own billing boundary: items it puts at 1,024 bytes consume one write unit, and 1,025 consumes two.
What JSON loses on the round trip
DynamoDB stores numbers as decimals with 38 digits of precision, so a JSON number is normalized rather than preserved. Written and read straight back:
{"price": 19.90} -> {"price": {"N": "19.9"}}
{"qty": 1.0} -> {"qty": {"N": "1"}}
{"limit": 1e5} -> {"limit": {"N": "100000"}}
{"id": 9007199254740993} -> {"id": {"N": "9007199254740993"}}That last line is the useful one. DynamoDB keeps the integer exactly, and JSON.parse('{"id":9007199254740993}') in Node gives you 9007199254740992. If IDs matter, store them as strings.
Two JSON documents DynamoDB will not take at all: an empty key ({"": "x"} raises ValidationException: Empty attribute name, and the same applies inside a nested map), and a number past the precision limit, which raises ValidationException: DynamoDB only supports precision up to 38 digits.
The one caveat
DynamoDB's types are a superset of JSON's. Binary (B) and Set (SS/NS/BS) attributes have no direct JSON equivalent, so sets serialize to arrays and binary to base64 when you convert back to plain JSON.
Working with it
You can operate on nested JSON attributes directly — filter on a map field, update one list element — without rewriting the whole item.
Go deeper
See DynamoDB JSON and marshalling, and convert between plain and DynamoDB JSON with the JSON converter. Download DynoTable to edit JSON items visually.
References
- Supported data types and naming rules in Amazon DynamoDB — Amazon DynamoDB Developer Guide
- Quotas in Amazon DynamoDB — Amazon DynamoDB Developer Guide
- DynamoDB Update – JSON, Expanded Free Tier, Flexible Scaling, Larger Items — AWS News Blog
Last verified 2026-07-13 against the official AWS documentation linked above.
Measured and reproduced 2026-07-28. The three byte counts come from our own item-size calculator and from the serialized request; the number round trips and both ValidationException strings are verbatim output from DynamoDB Local 3.3.0 via @aws-sdk/client-dynamodb 3.1095.0, whose message wording can differ from the live service.