GSI - Multi-Attribute Keys

Use up to 8 attributes in GSI composite keys to eliminate string concatenation and simplify data modeling.

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

FeatureTraditional Composite KeysMulti-Attribute Keys
Key creationManual concatenationNative DynamoDB
Backfill neededYesNo
Type safetyLost (all strings)Preserved
Parsing requiredYesNo
Max attributesUnlimited (in string)34 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

  1. Multi-attribute keys pattern - Amazon DynamoDB 2 3 4 5 6 7 8 9 10 11

  2. Multi-key support for Global Secondary Index in Amazon DynamoDB - AWS Database Blog 2 3 4 5 6

  3. While concatenated strings can include many attributes, DynamoDB’s 400KB item size limit and 2KB GSI key size limit constrain practical concatenation length.