dynobase-icon
Dynobase

DynamoDB Data Types: The Complete List of Attribute Types

Rafal Wilinski

Written by Rafal Wilinski

Last updated: October 23rd, 2026

Not sure what's really in your table? Dynobase's schema explorer finds nested paths, missing attributes and mixed types in your data. Schema explorer in Dynobase

DynamoDB supports ten attribute data types in three groups: scalar types (String, Number, Binary, Boolean and Null), document types (List and Map) and set types (String Set, Number Set and Binary Set). In DynamoDB JSON each value carries a type descriptor: S, N, B, BOOL, NULL, L, M, SS, NS or BS. Only String, Number and Binary can be used as key attributes of a table or index, and there is no date type.

All 10 DynamoDB data types

TypeDescriptorGroupExample in DynamoDB JSONCan be a key attribute
StringSScalar{"S": "Hello"}Yes
NumberNScalar{"N": "42.5"}Yes
BinaryBScalar{"B": "SGVsbG8="}Yes
BooleanBOOLScalar{"BOOL": true}No
NullNULLScalar{"NULL": true}No
ListLDocument{"L": [{"S": "a"}, {"N": "1"}]}No
MapMDocument{"M": {"city": {"S": "Lisbon"}}}No
String SetSSSet{"SS": ["red", "blue"]}No
Number SetNSSet{"NS": ["1", "2.5"]}No
Binary SetBSSet{"BS": ["U3Vubnk=", "UmFpbnk="]}No

You see descriptors in the low-level API, the AWS CLI, DynamoDB Streams records and exports in DynamoDB JSON format. Numbers travel as strings ("N": "42.5") so no precision is lost between languages, and binary values travel base64-encoded. The document clients in the AWS SDKs add and strip descriptors for you. To convert a payload by hand, paste it into the DynamoDB JSON converter.

This item uses all ten types:

Scalar types

A scalar holds exactly one value.

String (S)

Strings are Unicode, stored as UTF-8. A String that isn't a key attribute can be empty (""), and its length is bounded only by the 400 KB item size limit. Key attributes are stricter: a partition key value is 1 to 2,048 bytes and a sort key value is 1 to 1,024 bytes. Both limits count UTF-8 bytes, not characters.

DynamoDB compares and sorts strings by their UTF-8 bytes. Uppercase letters sort before lowercase ones ("Z" comes before "a"), and digits sort as text, so "10" comes before "9". If you store numbers in a string sort key, zero-pad them ("0009", "0010") or use a Number attribute. The sort key guide has more ordering patterns.

Number (N)

Numbers can be positive, negative or zero, with up to 38 significant digits. A value with more digits is rejected. The ranges are:

  • Positive: 1E-130 to 9.9999999999999999999999999999999999999E+125
  • Negative: -9.9999999999999999999999999999999999999E+125 to -1E-130

Every 64-bit integer fits, but not every 128-bit integer: 2^127 - 1 has 39 digits. Store values that need more precision as Strings.

Leading and trailing zeros are trimmed, so 007 is stored as 7 and 1.50 as 1.5. Phone numbers, ZIP codes and identifiers with leading zeros belong in a String. There is no NaN or Infinity, and the JavaScript and Python SDKs refuse to serialize them.

Numbers sort numerically in keys (2 before 10), and they support arithmetic in update expressions: SET visits = visits + :one or ADD visits :one increments a counter atomically.

Binary (B)

Binary attributes hold any bytes: compressed text, encrypted values, hashes, small images. In DynamoDB JSON and the CLI, binary values are base64-encoded. The SDKs encode for you, so you pass a Uint8Array or Buffer in JavaScript and bytes in Python. Size is counted on the raw bytes, not on the base64 text.

DynamoDB compares binary values byte by byte, treating each byte as unsigned, which matters when a binary attribute is a sort key. Non-key binary values can be empty. Binary key values follow the same 2,048-byte (partition key) and 1,024-byte (sort key) limits as strings.

Boolean (BOOL)

A Boolean is true or false. It can't be a key attribute, so it can't be the partition or sort key of a secondary index either. To query by a flag, write a String or Number attribute only on the items that have the flag set: that creates a sparse index (see global secondary indexes).

In a filter or condition expression, compare a Boolean explicitly: isActive = :yes with :yes set to {"BOOL": true}. A bare isActive is not a valid condition.

Null (NULL)

{"NULL": true} marks an attribute that exists but has no value. That is different from leaving the attribute out: attribute_exists(deletedAt) returns true for an attribute that holds NULL, and the attribute still takes up space. Unless you need that distinction, omit the attribute.

Never write NULL into an attribute that is a secondary index key. The index expects a String, Number or Binary there, so the write fails with a Type mismatch for Index Key ValidationException. An item that lacks the attribute is simply left out of the index.

Document types: List and Map

A List (L) is an ordered collection, like a JSON array. A Map (M) is an unordered collection of name-value pairs, like a JSON object. Elements can be of any type, mixed freely, and lists and maps can nest inside each other up to 32 levels deep. There is no limit on the number of elements beyond the item size limit, and empty lists and maps are allowed.

You can read and change part of a document without rewriting it by using document paths such as address.city or tags[0]:

Don't rely on the order of keys in a Map. If order matters, use a List, or store the document as a JSON string, which gives up filtering and updating fields inside it.

For large documents, AWS suggests compressing the value (GZIP, for example) into a Binary attribute, splitting the data across several items under one partition key, or storing the object in Amazon S3 and keeping its key in the item. Compressed values can't be used in filters.

Set types: SS, NS and BS

A set holds unique values of one scalar type: strings (SS), numbers (NS) or binary values (BS).

  • All elements have the same type. For mixed types, use a List.
  • Each value appears once.
  • Order is not preserved, so don't depend on the order you get back.
  • A set can't be empty. Writing an empty set fails with a ValidationException, although an empty string inside a set is allowed.

Update sets with ADD (add elements) and DELETE (remove elements), both of which take a set as their value. In conditions and filters, contains(badges, :b) tests membership and size(badges) counts the elements. With the JavaScript document client, pass a JavaScript Set to write a DynamoDB set; an array becomes a List.

Set (SS, NS, BS)List (L)
Element typesOne scalar typeAny, mixed
DuplicatesNot allowedAllowed
OrderNot preservedPreserved
Empty valueNot allowedAllowed
Add or remove by valueADD and DELETElist_append to add; REMOVE by index
Membership testcontains()contains()

How DynamoDB calculates item size

Item size is the sum of every attribute's name and value. It decides whether an item fits the 400 KB limit and how many read and write units each request consumes.

TypeSize
StringName bytes + UTF-8 bytes of the value
NumberName bytes + about 1 byte per two significant digits + 1 byte
BinaryName bytes + raw bytes (not the base64 length)
Boolean, NullName bytes + 1 byte
List, MapName bytes + 3 bytes + size of each element + 1 byte per element
String, Number and Binary SetName bytes + size of each element, with no per-element overhead

For example, pk = "USER#42" (2 + 7 bytes), age = 37 (3 + 1 + 1), verified = true (8 + 1) and badges = {"early-adopter", "reviewer"} (6 + 13 + 8) add up to about 50 bytes.

Attribute names are stored in every item, so short names (ts instead of lastModifiedTimestamp) cut storage and capacity on large tables. For storage billing, DynamoDB also adds 100 bytes of overhead per item, and every item copied into a secondary index is stored again. The item size calculator does the arithmetic, and the other quotas are collected on DynamoDB limits.

How the SDKs map native types

Each SDK converts between your language's types and DynamoDB types. The JavaScript DynamoDBDocumentClient from @aws-sdk/lib-dynamodb and the boto3 resource interface (which uses boto3.dynamodb.types.TypeSerializer) map them like this:

DynamoDB typeJavaScript (SDK v3 document client)Python (boto3)
Stringstringstr
Numbernumber, bigint, NumberValueint, decimal.Decimal (a float raises TypeError)
BinaryUint8Array, Bufferbytes, bytearray, Binary
Booleanbooleanbool
NullnullNone
ListArraylist, tuple
MapPlain object or Mapdict
String, Number, Binary SetSet of strings, numbers or Uint8Arrayset of str, int/Decimal or bytes

JavaScript (AWS SDK v3)

Reading back, a Number becomes a number, and integers beyond Number.MAX_SAFE_INTEGER come back as bigint. Values with more precision than a JavaScript number holds lose digits silently (or throw, if they are also large) unless you set wrapNumbers: true in unmarshallOptions, which returns every Number as an exact NumberValue. When writing, the document client throws on:

  • undefined values, unless you set removeUndefinedValues: true
  • empty Set objects, unless you set convertEmptyValues: true, which writes NULL instead
  • numbers outside the safe integer range; pass a bigint or a NumberValue
  • class instances, including Date, unless you set convertClassInstanceToMap: true, which turns a Date into an empty map, so convert dates yourself

Python (boto3)

boto3 maps every Number to decimal.Decimal, which keeps all 38 digits. It returns a Decimal even for whole numbers, and it refuses Python float values with TypeError: Float types are not supported. Use Decimal types instead. Build decimals from strings: Decimal(0.1) raises decimal.Inexact, because the float's exact binary value has 55 digits, while Decimal("0.1") works.

json.dumps can't serialize Decimal, so pass a default function when you return items as JSON. Binary values come back wrapped in boto3.dynamodb.types.Binary; its .value holds the bytes. More fixes are on Float types are not supported.

Java and Go

The Java Enhanced Client (AWS SDK for Java 2.x) converts fields through attribute converters. Use BigDecimal or BigInteger for values that need all 38 digits, and note that an Instant is stored as an ISO 8601 String by default. In Go, the attributevalue package (aws-sdk-go-v2) marshals []byte to Binary, other slices to Lists unless the field is tagged dynamodbav:",stringset" or dynamodbav:",numberset", and time.Time to an RFC 3339 String unless the field is tagged dynamodbav:",unixtime".

Storing dates and timestamps

DynamoDB has no date or time type. Use one of two formats:

FormatExampleBest for
ISO 8601 String in UTC"2026-10-23T14:05:00Z"Human-readable values; sort keys queried with begins_with or BETWEEN
Epoch seconds Number1792764300Compact storage, arithmetic and TTL, which requires this format

ISO strings sort chronologically only when every value has the same format, precision and time zone, so normalize to UTC with a Z suffix. Epoch milliseconds (from Date.now()) sort correctly but don't work for TTL, which reads the value as seconds. More formats and query examples are in working with timestamps in DynamoDB.

Which types can be keys

The partition key and sort key of a table must be String, Number or Binary. You declare them in AttributeDefinitions when you create the table, and their types can't change afterward. Index keys follow the same rule and must be top-level attributes, not paths inside a Map or List. Global secondary indexes also accept multi-attribute keys, up to four partition key and four sort key attributes, each one a String, Number or Binary. The DynamoDB keys guide covers how to choose them.

Every other attribute is schemaless. DynamoDB doesn't check that price is a Number in every item, so after a few application versions one attribute name can hold different types in different items. The Dynobase schema explorer samples real items and lists each attribute path with the types it holds and how often it is missing.

Frequently Asked Questions

What are the data types in DynamoDB?

DynamoDB has ten data types: String (S), Number (N), Binary (B), Boolean (BOOL) and Null (NULL) are scalars; List (L) and Map (M) are document types; and String Set (SS), Number Set (NS) and Binary Set (BS) are set types.

Does DynamoDB have a date or datetime type?

No. Store dates as ISO 8601 strings in UTC, such as 2026-10-23T14:05:00Z, or as Unix epoch numbers. TTL only works with a Number holding epoch seconds.

Which data types can a DynamoDB primary key use?

Only String, Number and Binary. The same rule applies to the key attributes of local and global secondary indexes, which must also be top-level attributes.

Can DynamoDB store empty strings, lists or sets?

Empty strings and empty binary values are allowed in attributes that aren't keys, and empty lists and maps are allowed anywhere. Empty sets are not allowed: writing one fails with a ValidationException.

Why does boto3 return Decimal instead of int or float?

boto3 maps the DynamoDB Number type to decimal.Decimal so that all 38 digits of precision survive the round trip. It rejects Python floats, so convert them with Decimal(str(value)) or parse JSON with parse_float=Decimal.

What is the difference between a List and a Set in DynamoDB?

A List is ordered, allows duplicates and can mix types. A Set holds unique values of a single type (strings, numbers or binary), has no order, can't be empty, and supports atomic ADD and DELETE of elements.

Dynobase is a Professional GUI Client for DynamoDB

Start your 7-day free trial today

Product Features

Download
/
Pricing
/
Member Portal
/
Privacy
/
EULA
/
Twitter
© 2026 Dynobase