What are multi-attribute keys?
Multi-attribute keys allow you to create Global Secondary Index (GSI) partition and sort keys composed of up to four attributes each—for a total of up to eight attributes per GSI key structure. This feature eliminates the need for manually concatenating values into synthetic keys, reduces client-side code complexity, and makes it easier to model data and add new access patterns.1
The problem multi-attribute keys solve
Before this feature, querying DynamoDB by multiple attributes required awkward workarounds. Each GSI key (partition or sort) was limited to a single attribute. If you needed to query by multiple hierarchical dimensions—like finding all orders for a specific customer with a particular status on a given date—you had two bad options:2
Option 1: String concatenation in application code
You manually built synthetic keys by concatenating multiple values with delimiters:
// Creating synthetic keys in your application
const gsiPartitionKey = `CUSTOMER#${customerId}#STATUS#${status}`;
const gsiSortKey = `${orderDate}#${orderId}`;
await dynamodb.putItem({
Item: {
orderId: 'order-123',
customerId: 'cust-456',
status: 'PENDING',
orderDate: '2024-11-20',
// Synthetic keys for GSI
GSI_PK: gsiPartitionKey, // "CUSTOMER#cust-456#STATUS#PENDING"
GSI_SK: gsiSortKey // "2024-11-20#order-123"
}
});
// Reading requires parsing the synthetic keys back
const items = await dynamodb.query({...});
items.forEach(item => {
// Parse concatenated string to get original values
const [, customerId, , status] = item.GSI_PK.split('#');
const [orderDate, orderId] = item.GSI_SK.split('#');
});
Problems with this approach:
- Every write requires building concatenated strings in application code
- Every read requires parsing strings back into separate values
- All attributes become strings (lose type safety for numbers, dates, booleans)
- Adding a new GSI to an existing table requires backfilling all items with synthetic keys
- Code becomes cluttered with string manipulation logic
- Harder to maintain as data models evolve
Option 2: Use FilterExpression (inefficient)
Query by one attribute and filter the rest client-side:
// Query by customerId, then filter by status (reads all customer orders)
const result = await dynamodb.query({
KeyConditionExpression: 'customerId = :cust',
FilterExpression: '#status = :status AND orderDate = :date',
ExpressionAttributeValues: {
':cust': 'cust-456',
':status': 'PENDING',
':date': '2024-11-20'
}
});
Problems with this approach:
- You pay for reading all items before filtering (consumed capacity based on total items scanned)
- Slower performance as dataset grows
- Cannot efficiently paginate filtered results
The multi-attribute keys solution:
With multi-attribute keys, DynamoDB handles the composite key logic natively. You write items using natural domain attributes, and DynamoDB automatically indexes them without string concatenation:1
// Write items with natural attributes - no concatenation needed
await dynamodb.putItem({
Item: {
orderId: 'order-123',
customerId: 'cust-456',
status: 'PENDING',
orderDate: '2024-11-20'
// No synthetic keys needed - GSI uses these attributes directly
}
});
// Query using native attributes
const result = await dynamodb.query({
IndexName: 'CustomerStatusDateIndex',
KeyConditionExpression: 'customerId = :cust AND #status = :status AND orderDate = :date',
ExpressionAttributeNames: { '#status': 'status' },
ExpressionAttributeValues: {
':cust': 'cust-456',
':status': 'PENDING',
':date': '2024-11-20'
}
});
The code stays clean, your data stays typed, and your queries stay efficient.
Traditional vs. multi-attribute keys comparison
| Feature | Traditional Composite Keys | Multi-Attribute Keys |
|---|---|---|
| Key creation | Manual concatenation | Native DynamoDB |
| Backfill needed | Yes | No |
| Type safety | Lost (all strings) | Preserved |
| Parsing required | Yes | No |
| Max attributes | Unlimited (in string)3 | 4 PK + 4 SK |
When to use multi-attribute keys
Multi-attribute keys are the right choice when:
- You need to query by multiple attributes together: Your access pattern requires filtering by seller AND region AND date, not just one at a time
- Your data has natural hierarchies: Orders organized by seller → region → date
- You’re building new GSIs on existing tables: Avoid backfilling synthetic keys—multi-attribute keys work with your existing attributes
- Hot partitions are a concern: Increase partition key cardinality by using multiple attributes (like customerId + status). This creates unique partition key values for each customer-status combination, distributing what would otherwise concentrate on a high-traffic customer across multiple partitions based on their order statuses.
How multi-attribute keys work
Partition keys
DynamoDB hashes all partition key attributes together to determine data distribution. When you specify multiple partition key attributes (up to four), queries must provide all partition key attributes using equality conditions (=). You cannot query with only some partition key attributes or use inequality operators on partition key attributes.1
Example: A GSI with partition key composed of sellerId + region requires both values in every query:
// Valid query
KeyConditionExpression: 'sellerId = :seller AND region = :region'
// Invalid - missing region
KeyConditionExpression: 'sellerId = :seller'
// Invalid - inequality on partition key
KeyConditionExpression: 'sellerId = :seller AND region > :region'
Sort keys
Sort key attributes must be queried left-to-right in the order they’re defined in the GSI. You can query using the first attribute alone, the first two attributes, the first three attributes, or all four—but you cannot skip attributes in the middle.1
Example: A GSI with sort key composed of orderDate + status + orderId:
// Valid patterns
orderDate = '2024-11-20'
orderDate = '2024-11-20' AND status = 'SHIPPED'
orderDate = '2024-11-20' AND status = 'SHIPPED' AND orderId = 'order-123'
// Invalid patterns
status = 'SHIPPED' (skips orderDate)
orderDate = '2024-11-20' AND orderId = 'order-123' (skips status)
Inequality conditions
Inequality operators (>, >=, <, <=, BETWEEN, begins_with()) can only be used on the last sort key attribute in your query. Once you use an inequality operator, you cannot add any additional sort key conditions after it.1
Valid examples:
// Inequality on first sort key attribute
orderDate >= '2024-11-01'
// Equality conditions followed by inequality
orderDate = '2024-11-20' AND status = 'SHIPPED' AND orderId > 'order-100'
// Range query
orderDate BETWEEN '2024-11-01' AND '2024-11-30'
Invalid examples:
// Cannot add conditions after inequality
orderDate > '2024-11-01' AND status = 'SHIPPED'
// Cannot use multiple inequalities
orderDate > '2024-11-01' AND status > 'PENDING'
Best practices
Design for query patterns first
Before creating GSIs, identify your top 3-5 most common query patterns, understand their frequency and performance requirements. Design your base table for uniqueness and use GSIs to optimize for composite key patterns.2
Choose key order carefully
The order of attributes in your GSI directly impacts which queries you can run. You don’t need to use all four partition keys and four sort keys—choose the combination that matches your access patterns. Order sort key attributes from most general to most specific to maximize query flexibility.1
Use native data types
One of the most powerful aspects of multi-attribute keys is support for native data types. Use Number types for timestamps, quantities, and numeric comparisons to enable proper sorting and mathematical operations. Avoid converting values to strings unless necessary.2
Plan for sparse indexes
GSIs with multi-attribute keys are sparse—if any component of a composite key is missing, items won’t be indexed. Use this to your advantage by only indexing items that need the access pattern, reducing storage costs.2
No backfilling needed
When you add a new GSI with multi-attribute keys to an existing table, DynamoDB automatically indexes all existing items using their natural attributes. You don’t need to update items with synthetic keys.1
Limitations
Query constraints
- All partition key attributes must be provided in queries with equality conditions—no partial queries or inequalities on partition keys1
- Sort key attributes must be queried left-to-right without skipping any in the middle1
- Inequality operators can only be used on the last sort key attribute in your query1
Attribute and index limits
- Maximum of 4 partition key attributes and 4 sort key attributes per GSI2
- Only available for Global Secondary Indexes—not for base table keys or Local Secondary Indexes1
- Key attributes must be scalar types (String, Number, or Binary)—no Sets, Lists, or Maps
Sparse index behavior
Items missing any component of a multi-attribute key won’t be indexed—same sparse behavior as single-attribute GSIs.2
Migration and compatibility
- No automatic migration from existing concatenated key GSIs—you must create a new GSI
- Third-party tools, ORMs, and infrastructure-as-code frameworks may have limited support as of November 2025
- Console visualization may differ from single-attribute keys
Footnotes
-
Multi-attribute keys pattern - Amazon DynamoDB ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11
-
Multi-key support for Global Secondary Index in Amazon DynamoDB - AWS Database Blog ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
While concatenated strings can include many attributes, DynamoDB’s 400KB item size limit and 2KB GSI key size limit constrain practical concatenation length. ↩