DynamoDB Data Types and Attributes: Complete Guide (2025)
DynamoDB Data Types and Attributes: Complete Guide (2025)
Understanding DynamoDB’s data types and attributes is essential for effective data modeling and optimizing your NoSQL database performance. Unlike traditional relational databases with rigid schemas, DynamoDB offers a flexible attribute structure that requires careful planning to use effectively.
Table of Contents
- Understanding DynamoDB’s Data Model
- Scalar Data Types
- Document Data Types
- Set Data Types
- Binary Data Type
- Special Data Types
- Attributes and Item Size Limits
- Type Descriptors in DynamoDB
- Data Type Conversions
- Best Practices for Data Types
- Common Pitfalls and Solutions
- Performance Considerations
- Real-World Examples
- Conclusion
Understanding DynamoDB’s Data Model
DynamoDB is a NoSQL database with a flexible schema design that allows each item to have different attributes. Unlike relational databases that require predefined tables with fixed columns, DynamoDB items can:
- Have different attributes from other items in the same table
- Add or remove attributes at any time
- Vary in structure while being in the same table
This flexibility comes with the responsibility of understanding how to properly model your data using DynamoDB’s supported data types.
Key Concepts
- Tables: Collections of items (similar to rows in relational databases)
- Items: Groups of attributes with a unique identifier (primary key)
- Attributes: Fundamental data elements, each with a name and a type
- Primary Key: Required attribute(s) that uniquely identify an item (partition key + optional sort key)
Scalar Data Types
Scalar types represent a single, atomic value. DynamoDB supports the following scalar types:
String (S)
Strings are Unicode characters with UTF-8 binary encoding. They have no theoretical maximum length, though the practical limit is 400KB (the maximum item size).
// String attribute example
{
"ProductName": "Wireless Headphones",
"Description": "Premium noise-canceling wireless headphones with 20-hour battery life."
}
Best Practices for Strings:
- Use strings for textual data and identifiers
- Consider using prefixes for keys (e.g., “USER#123”, “ORDER#456”)
- Strings are case-sensitive in comparisons
Number (N)
Number types can represent integers or floating-point values. They are stored with variable precision and can be positive, negative, or zero.
// Number attribute examples
{
"Price": 99.99,
"Quantity": 5,
"Rating": 4.7,
"NegativeValue": -42
}
Important Considerations:
- Numbers are stored as strings in DynamoDB’s JSON representation
- Maximum precision is 38 digits
- No distinction between integers and decimals
- Leading zeros are not preserved
Boolean (BOOL)
Boolean values represent true or false.
// Boolean attribute examples
{
"IsAvailable": true,
"IsDeletedProduct": false
}
Usage Tips:
- Great for flags and status indicators
- Can be used in condition expressions
- Preferred over strings like “yes”/“no” for boolean logic
Null (NULL)
Represents an attribute with an unknown or undefined value.
// Null attribute example
{
"MiddleName": null,
"LastPurchaseDate": null
}
When to Use Null:
- Represent missing or undefined values
- Indicate that an attribute exists but has no value
- Note that null attributes still consume storage and write capacity
Document Data Types
Document types can store complex nested structures, similar to JSON objects.
Map (M)
Maps are unordered collections of name-value pairs, similar to JSON objects. They can contain any other data type, including nested maps.
// Map attribute example
{
"Address": {
"Street": "123 Main St",
"City": "Seattle",
"State": "WA",
"ZipCode": "98101",
"Coordinates": {
"Latitude": 47.6062,
"Longitude": -122.3321
}
}
}
Benefits of Maps:
- Organize related attributes together
- Create hierarchical data structures
- Encapsulate complex objects
Accessing Map Elements:
// Using document paths to access nested elements
ExpressionAttributeNames: {
"#addr": "Address",
"#city": "City"
},
UpdateExpression: "SET #addr.#city = :newCity",
ExpressionAttributeValues: {
":newCity": "Portland"
}
List (L)
Lists are ordered collections of values that can contain any other data type, including nested lists.
// List attribute example
{
"RecentOrders": [
"ORD-001",
"ORD-002",
"ORD-003"
],
"PhoneNumbers": [
{
"Type": "Home",
"Number": "555-1234"
},
{
"Type": "Work",
"Number": "555-5678"
}
]
}
Benefits of Lists:
- Store ordered collections of data
- Maintain sequence and position
- Mix different data types within a single list
Accessing List Elements:
// Using list indices to access elements
UpdateExpression: "SET PhoneNumbers[1].Number = :newNumber",
ExpressionAttributeValues: {
":newNumber": "555-9876"
}
Important Considerations for Document Types:
- Document types can be nested up to 32 levels deep
- They count toward the 400KB item size limit
- Individual elements can be accessed and updated independently
- Perfect for denormalizing data in NoSQL design patterns
Set Data Types
Sets are unordered collections of unique scalar values of the same type. DynamoDB supports three set types:
String Set (SS)
Collections of unique String values.
// String set example
{
"Categories": ["Electronics", "Accessories", "Headphones"]
}
Number Set (NS)
Collections of unique Number values.
// Number set example
{
"PricePoints": [19.99, 29.99, 39.99, 49.99]
}
Binary Set (BS)
Collections of unique Binary values.
// Binary set example (represented in Base64)
{
"FileHashes": ["U2VjcmV0IGRhdGE=", "TW9yZSBzZWNyZXQgZGF0YQ=="]
}
Key Characteristics of Sets:
- All elements must be of the same type
- Each element must be unique
- Empty sets are not allowed
- Order is not preserved
- Great for unique collections like tags, categories, or IDs
Note: DynamoDB does not support Boolean sets, Map sets, List sets, or mixed-type sets.
Binary Data Type
Binary (B) data can store any binary data such as compressed text, encrypted data, or images.
// Binary attribute example (Base64-encoded)
{
"Thumbnail": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="
}
Use Cases for Binary Data:
- Store small images or thumbnails
- Encrypted data
- Compressed text
- Digital signatures
- Protocol buffers
Considerations:
- Limited to 400KB as part of the item size limit
- Stored and retrieved as Base64-encoded in JSON
- Client-side encoding/decoding is usually required
Special Data Types
DynamoDB Streams Specific Types
When working with DynamoDB Streams, you’ll encounter additional special types:
Boolean (BOOL)
Used the same way as in regular DynamoDB operations.
Null (NULL)
Used the same way as in regular DynamoDB operations.
Blob (B)
Similar to the Binary type, used for streaming binary data.
Blob Set (BS)
A set of unique Blob values.
Attributes and Item Size Limits
Understanding DynamoDB’s size limits is crucial for effective data modeling:
- Item Size Limit: 400KB (including attribute names and values)
- Maximum Number of Attributes: No fixed limit, but constrained by the 400KB item size
- Attribute Name Length: Up to 64KB
- Maximum Depth for Document Types: 32 levels of nesting
Strategies for Handling Large Items
-
Splitting Large Items:
- Break large items into smaller, related items
- Use the same partition key with different sort keys
- Use a linking strategy to maintain relationships
-
Compression:
- Compress large text or binary data before storing
- Use shortened attribute names for frequently used attributes
- Consider storing large content in S3 and keeping references in DynamoDB
-
Attribute Selection:
- Only store attributes you need to query or retrieve
- Move rarely accessed attributes to a separate item
- Use sparse indexes for large, optional attributes
Type Descriptors in DynamoDB
When interacting with DynamoDB through APIs or SDKs, you’ll often need to specify the data type of each attribute using type descriptors:
// Using AWS SDK for JavaScript v3
const item = {
ProductId: { S: "PROD-123" },
Name: { S: "Wireless Headphones" },
Price: { N: "99.99" },
InStock: { BOOL: true },
Categories: { SS: ["Electronics", "Audio", "Bluetooth"] },
Details: {
M: {
Color: { S: "Black" },
Weight: { N: "0.3" },
Dimensions: {
M: {
Length: { N: "7.5" },
Width: { N: "6.1" },
Height: { N: "3.2" }
}
}
}
},
PreviousPrices: { NS: ["89.99", "94.99", "109.99"] },
ImageData: { B: "iVBORw0KGgoAA..." }, // Base64-encoded binary data
Features: {
L: [
{ S: "Noise cancellation" },
{ S: "20-hour battery life" },
{ S: "Fast charging" }
]
}
};
Dynomate: Modern DynamoDB GUI Client
Built for real developer workflows with AWS profile integration, multi-session support, and team collaboration.
No account needed. Install and start using immediately.
- Table browsing across regions
- Flexible query & scan interface
- AWS API logging & debugging
Many SDKs also provide utilities to convert between JavaScript objects and DynamoDB attribute values:
// Using AWS SDK for JavaScript v3
import { marshall, unmarshall } from "@aws-sdk/util-dynamodb";
// Convert JavaScript object to DynamoDB item
const jsObject = {
ProductId: "PROD-123",
Name: "Wireless Headphones",
Price: 99.99,
InStock: true
};
const dynamoDBItem = marshall(jsObject);
// Result: { ProductId: { S: "PROD-123" }, Name: { S: "Wireless Headphones" }, ... }
// Convert DynamoDB item back to JavaScript object
const backToJsObject = unmarshall(dynamoDBItem);
// Result: { ProductId: "PROD-123", Name: "Wireless Headphones", ... }
Data Type Conversions
DynamoDB doesn’t perform automatic type conversions. Type mismatches can cause operation failures. Here are common scenarios:
Number Type Conversions
Numbers are stored as strings in DynamoDB, and precision is maintained for mathematical operations:
// In JavaScript
const price = 9.99;
// In DynamoDB (stored as)
{ "Price": { "N": "9.99" } }
To perform mathematical operations:
// Add 10 to the price
UpdateExpression: "SET Price = Price + :increase",
ExpressionAttributeValues: {
":increase": { "N": "10" }
}
// Result: Price becomes 19.99
String and Number Comparisons
When comparing values, data types matter:
// This condition will fail if Quantity is stored as a number
FilterExpression: "Quantity = :val",
ExpressionAttributeValues: {
":val": { "S": "5" } // String "5" won't match Number 5
}
// Correct version if Quantity is a number
ExpressionAttributeValues: {
":val": { "N": "5" }
}
Empty Values
DynamoDB has specific rules for empty values:
- Empty strings are allowed and are valid String values
- Empty sets are not allowed
- Empty lists and maps are allowed
- Zero is a valid Number value (not considered “empty”)
Best Practices for Data Types
1. Choose the Right Type for Your Data
- Use strings for text, identifiers, and when you need case-sensitivity
- Use numbers for quantities, measurements, and values you’ll perform calculations on
- Use booleans for flags and status indicators
- Use lists for ordered collections where position matters
- Use maps for complex, hierarchical data structures
- Use sets for unique collections of values
2. Structure Your Data for Access Patterns
- Place frequently accessed attributes at the top level for easier access
- Group related attributes in maps for better organization
- Use lists for collections that have a natural ordering
- Design your data structure based on how you’ll query it
3. Be Consistent with Data Types
- Maintain consistent data types across similar attributes
- Document your type choices for team reference
- Use appropriate validation in your application code
- Consider implementing a schema validation layer
4. Optimize for Storage and Cost
- Use shorter attribute names to reduce storage costs
- Consider compressing large text or binary data
- Avoid storing unnecessary data
- Use sparse attributes for optional fields
Common Pitfalls and Solutions
1. Type Mismatch Errors
Pitfall: Using the wrong type in conditions or updates.
// Error: Comparing a String to a Number
KeyConditionExpression: "ProductId = :id AND Price > :min",
ExpressionAttributeValues: {
":id": { "S": "PROD-123" },
":min": { "S": "50" } // Error: Price is a Number attribute
}
Solution: Ensure type consistency.
// Fixed: Use the correct type for Price
ExpressionAttributeValues: {
":id": { "S": "PROD-123" },
":min": { "N": "50" }
}
2. Empty String vs. Null vs. Not Present
Pitfall: Confusing empty strings, null values, and missing attributes.
Solution: Be deliberate about your approach:
- Empty string: An attribute exists with a zero-length value
- Null: An attribute exists with an unknown or undefined value
- Not present: The attribute doesn’t exist at all
3. Set vs. List Confusion
Pitfall: Using the wrong collection type.
Solution: Choose based on your needs:
- Use sets when you need uniqueness and don’t care about order
- Use lists when order matters or you need duplicate values
4. Document Path Syntax Errors
Pitfall: Incorrect syntax when accessing nested attributes.
Solution: Use the correct document path syntax:
// Correct syntax for nested updates
UpdateExpression: "SET #addr.#city = :city, Details.Dimensions.Height = :height",
ExpressionAttributeNames: {
"#addr": "Address",
"#city": "City"
},
ExpressionAttributeValues: {
":city": { "S": "Portland" },
":height": { "N": "3.5" }
}
Performance Considerations
Different data types can affect performance in various ways:
Query Performance
- Primary Keys: String and Number types are most efficient for key attributes
- Indexes: Consider the data types used in secondary indexes
- Filters: Filtering on scalar types is more efficient than on document types
Storage Efficiency
- Strings: Variable length, so only pay for what you use
- Numbers: Generally more space-efficient than storing numbers as strings
- Document Types: Allow you to store related data together, which can improve query efficiency
Write Throughput
- Item Size: Larger items consume more write capacity
- Sets vs. Lists: Updating large sets can consume more write capacity than updating lists
- Document Types: Updates to nested attributes can be more efficient than updating entire items
Real-World Examples
User Profile Example
{
"UserId": { "S": "USER-123" },
"Email": { "S": "user@example.com" },
"Name": { "S": "John Smith" },
"Age": { "N": "32" },
"IsActive": { "BOOL": true },
"JoinDate": { "S": "2025-01-15T14:30:00Z" },
"Address": {
"M": {
"Street": { "S": "123 Main St" },
"City": { "S": "Seattle" },
"State": { "S": "WA" },
"ZipCode": { "S": "98101" }
}
},
"Preferences": {
"M": {
"Theme": { "S": "Dark" },
"NotificationsEnabled": { "BOOL": true },
"FavoriteCategories": {
"SS": ["Electronics", "Books", "Music"]
}
}
},
"PhoneNumbers": {
"L": [
{ "M": {
"Type": { "S": "Home" },
"Number": { "S": "555-1234" }
}},
{ "M": {
"Type": { "S": "Work" },
"Number": { "S": "555-5678" }
}}
]
},
"RecentOrderIds": {
"SS": ["ORDER-001", "ORDER-002", "ORDER-003"]
}
}
Product Catalog Example
{
"ProductId": { "S": "PROD-456" },
"Name": { "S": "Wireless Headphones" },
"Brand": { "S": "AudioTech" },
"Price": { "N": "99.99" },
"Discount": { "N": "15.00" },
"InStock": { "BOOL": true },
"Rating": { "N": "4.7" },
"Categories": {
"SS": ["Electronics", "Audio", "Bluetooth", "Accessories"]
},
"Specifications": {
"M": {
"Color": { "S": "Black" },
"Weight": { "N": "0.3" }, // kg
"BatteryLife": { "N": "20" }, // hours
"Connectivity": {
"L": [
{ "S": "Bluetooth 5.0" },
{ "S": "3.5mm Audio Jack" }
]
},
"Dimensions": {
"M": {
"Length": { "N": "7.5" },
"Width": { "N": "6.1" },
"Height": { "N": "3.2" }
}
}
}
},
"Features": {
"L": [
{ "S": "Active Noise Cancellation" },
{ "S": "Fast Charging" },
{ "S": "Voice Assistant Support" }
]
},
"Variants": {
"L": [
{
"M": {
"Color": { "S": "White" },
"SKU": { "S": "SKU-789-W" },
"InStock": { "BOOL": true }
}
},
{
"M": {
"Color": { "S": "Red" },
"SKU": { "S": "SKU-789-R" },
"InStock": { "BOOL": false }
}
}
]
},
"CreatedAt": { "S": "2025-01-10T09:15:00Z" },
"UpdatedAt": { "S": "2025-03-05T14:30:00Z" },
"Thumbnail": { "B": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==" }
}
Conclusion
DynamoDB’s flexible data types allow you to model your data in ways that best fit your application’s needs. By understanding the characteristics and best practices for each type, you can create efficient, scalable, and cost-effective database designs.
Key takeaways:
- Choose the appropriate data type for your use case
- Design your data structure around your access patterns
- Be mindful of DynamoDB’s size limits and type constraints
- Use document types to organize related data together
- Maintain consistency in your type usage across your application
Familiar with these Dynamodb Challenges ?
- Writing one‑off scripts for simple DynamoDB operations
- Constantly switching between AWS profiles and regions
- Sharing and managing database operations with your team
You should try Dynomate GUI Client for DynamoDB
- Create collections of operations that work together like scripts
- Seamless integration with AWS SSO and profile switching
- Local‑first design with Git‑friendly sharing for team collaboration
For more information on optimizing your DynamoDB implementation, check out our related articles:
- Partition Key vs Sort Key in DynamoDB
- Global Secondary Index (GSI) in DynamoDB
- DynamoDB Best Practices
Ready to simplify your DynamoDB development experience? Try Dynomate - our powerful GUI client that makes working with DynamoDB data types easier than ever.