What is data length contraction?
Amazon DynamoDB is a schema-less database, where the total size of an item is the sum of the lengths of its attribute names and values.1 Reducing the data length of attribute names can significantly reduce storage costs and lower provisioned throughput requirements.
Key concept: DynamoDB charges you for the entire item size, including:
- Attribute names (the keys)
- Attribute values (the data)
- Data type descriptors
This means verbose attribute names directly increase your costs, especially at scale.
When to use data length contraction
High-impact scenarios:
- High-volume tables - Millions or billions of items where savings multiply
- Wide tables - Many attributes per item (>10 attributes)
- Frequently updated items - Write-heavy workloads where WCU costs are significant
- Hot data - Frequently read data where RCU costs matter
- Cost-sensitive applications - Where every optimization counts
Low-impact scenarios:
- Small tables (<1M items) where savings are minimal
- Tables with few attributes (<5 attributes)
- Rarely accessed cold data where throughput costs are already low
Implementation strategies
Strategy 1: Abbreviate common words
Replace common long words with standard abbreviations:
Before:
{
"product_identifier": "prod-12345",
"product_description": "Wireless mouse",
"manufacturer_name": "TechCorp",
"inventory_quantity": 150,
"last_updated_timestamp": "2025-11-22T10:00:00Z",
"price_in_cents": 2999,
"is_available_for_purchase": true
}
After:
{
"prod_id": "prod-12345",
"desc": "Wireless mouse",
"mfr": "TechCorp",
"qty": 150,
"updated": "2025-11-22T10:00:00Z",
"price": 2999,
"avail": true
}
Savings: 88 bytes per item → 41 bytes = 47 bytes saved (53% reduction)
Strategy 2: Single-letter keys for nested objects
For nested objects with predictable structure, use single letters:
Before:
{
"user_id": "user-123",
"shipping_address": {
"street_address": "123 Main St",
"city_name": "Seattle",
"state_code": "WA",
"postal_code": "98101"
},
"billing_address": {
"street_address": "456 Oak Ave",
"city_name": "Portland",
"state_code": "OR",
"postal_code": "97201"
}
}
After:
{
"uid": "user-123",
"ship": {
"st": "123 Main St",
"c": "Seattle",
"s": "WA",
"z": "98101"
},
"bill": {
"st": "456 Oak Ave",
"c": "Portland",
"s": "OR",
"z": "97201"
}
}
Savings: 159 bytes → 87 bytes = 72 bytes saved (45% reduction)
Strategy 3: Eliminate redundant prefixes
Remove table-specific prefixes that are implied by context:
Before:
{
"order_id": "order-789",
"order_date": "2025-11-22",
"order_total": 99.99,
"order_status": "shipped",
"order_items": [...]
}
After:
{
"id": "order-789",
"date": "2025-11-22",
"total": 99.99,
"status": "shipped",
"items": [...]
}
Savings: 54 bytes → 30 bytes = 24 bytes saved (44% reduction)
Best practices
Maintain a mapping document
Create and maintain a clear mapping between shortened and full attribute names:
// attribute-mapping.js
const ATTRIBUTE_MAPPING = {
// User attributes
'uid': 'user_id',
'email': 'email_address',
'fname': 'first_name',
'lname': 'last_name',
'created': 'created_timestamp',
// Product attributes
'prod_id': 'product_identifier',
'desc': 'product_description',
'mfr': 'manufacturer_name',
'qty': 'inventory_quantity',
'price': 'price_in_cents',
// Order attributes
'oid': 'order_id',
'uid': 'user_id',
'total': 'order_total_cents',
'status': 'order_status',
'ship': 'shipping_address',
'bill': 'billing_address'
};
// Helper function to expand abbreviations for readability
function expandAttributes(item) {
const expanded = {};
for (const [key, value] of Object.entries(item)) {
const fullKey = ATTRIBUTE_MAPPING[key] || key;
expanded[fullKey] = value;
}
return expanded;
}
Use abstraction layers
Create data access layers that handle the translation:
# data_access_layer.py
class DynamoDBMapper:
"""Abstract DynamoDB access with attribute name translation."""
COMPACT_TO_VERBOSE = {
'uid': 'user_id',
'email': 'email_address',
'fname': 'first_name',
'lname': 'last_name',
'created': 'created_timestamp'
}
VERBOSE_TO_COMPACT = {v: k for k, v in COMPACT_TO_VERBOSE.items()}
@classmethod
def to_dynamodb(cls, verbose_item):
"""Convert verbose attribute names to compact for storage."""
return {
cls.VERBOSE_TO_COMPACT.get(k, k): v
for k, v in verbose_item.items()
}
@classmethod
def from_dynamodb(cls, compact_item):
"""Convert compact attribute names to verbose for application use."""
return {
cls.COMPACT_TO_VERBOSE.get(k, k): v
for k, v in compact_item.items()
}
# Usage
user_data = {
'user_id': 'user-123',
'email_address': 'user@example.com',
'first_name': 'John',
'last_name': 'Doe',
'created_timestamp': '2025-11-22T10:00:00Z'
}
# Store in DynamoDB with compact names
compact_data = DynamoDBMapper.to_dynamodb(user_data)
table.put_item(Item=compact_data)
# Stored as: {'uid': 'user-123', 'email': 'user@example.com', ...}
# Retrieve and expand for application use
response = table.get_item(Key={'uid': 'user-123'})
verbose_data = DynamoDBMapper.from_dynamodb(response['Item'])
# Returns: {'user_id': 'user-123', 'email_address': 'user@example.com', ...}
Balance readability and optimization
Good abbreviations:
- Industry-standard abbreviations (qty, desc, addr)
- Single-letter codes for well-known fields (c for city, s for state)
- Shortened forms that retain meaning (prod, mfr, inv)
Avoid:
- Ambiguous single letters without context (a, b, x, y)
- Inconsistent abbreviation patterns
- Cryptic codes that require constant reference
Document your conventions
Include attribute mapping in your codebase documentation:
User Table (users)
| Compact | Full Name | Description |
|---|---|---|
| uid | user_id | Unique user identifier |
| email_address | User email address | |
| fname | first_name | User first name |
| lname | last_name | User last name |
| created | created_timestamp | Account creation timestamp |
| status | account_status | Account status (active/suspended/deleted) |
Trade-offs to consider
Advantages
- Direct cost savings - Reduced storage and throughput costs
- Performance benefits - Smaller items transfer faster over the network
- Capacity efficiency - More items processed per capacity unit
- Compounding savings - Benefits multiply with table size
Disadvantages
-
Reduced readability - Compact names are less self-documenting
-
Increased complexity - Requires mapping layer and documentation
-
Team onboarding - New developers need to learn attribute mappings
-
Debugging difficulty - Less obvious what data represents when viewing raw items
-
Migration effort - Existing tables require careful migration planning