DynamoDB composite keys: design and code examples

Written by Charlie Fish
Last updated: October 23rd, 2026
A DynamoDB composite primary key consists of a partition key and a sort key. The pair uniquely identifies each item, while items sharing the partition key form a collection you can query together. GetItem, UpdateItem and DeleteItem require both values; Query requires the partition key and optionally a sort-key condition.
What is a composite key in DynamoDB?
The key is not a third field stored alongside its parts. Both key attributes are ordinary, visible attributes in the item, and together they form its identity. A table with pk and sk can contain these records:
| pk | sk | Record |
|---|---|---|
| CUSTOMER#42 | PROFILE | Customer profile |
| CUSTOMER#42 | ORDER#2026-10-01#100 | An order |
| CUSTOMER#42 | ORDER#2026-10-03#101 | Another order |
| CUSTOMER#77 | PROFILE | Another customer's profile |
The two PROFILE sort-key values are valid because their partition keys differ. Two items with pk = CUSTOMER#42 and sk = PROFILE cannot coexist: they have the same full primary key. An unconditional put at that key replaces the previous item.
A composite sort key means something different. It is one sort-key value built from several application fields, such as ORDER#2026-10-01#100. The table still has exactly two key attributes, pk and sk. DynamoDB treats that sort-key value as a String; your application defines its components and separators. AWS describes this approach in its composite sort-key building block.
Why use a composite primary key?
Use it when the application needs both individual records and a related collection. An order-history screen knows a customer ID and wants orders by date. An item-details screen knows the customer ID and exact order key. The same table schema supports both operations without scanning unrelated customers.
The sort key narrows the collection before DynamoDB reads the matching items. A prefix condition can select only orders, and a range can select a time window. This differs from a filter expression, which discards results after reading them and does not refund read capacity.
A composite key is not automatically better for every table. If the only operation is reading a session by a random token, a simple primary key may be sufficient. A composite key also requires callers to know both components for individual updates and deletes. Compare the alternatives in the DynamoDB keys overview.
Composite key vs other key types
| Comparison | Difference |
|---|---|
| Composite key vs primary key | A composite key is one form of primary key. The other form contains a partition key alone. |
| Composite key vs partition key | The partition key is only one component when the table has a sort key. It identifies a collection, not one item. |
| Composite primary key vs composite sort key | The former uses two attributes; the latter encodes multiple values in one sort-key attribute. |
| Table key vs GSI key | The table key must be unique. A GSI key supplies another access path and need not be unique. |
GSIs also support native multi-attribute keys: up to four partition-key attributes and four sort-key attributes. That does not expand a base table's key schema. A base-table hierarchy still needs an encoded sort key or separate items; see working with GSIs when native multi-attribute indexing suits an alternate query.
Hierarchical sort keys
Order components from the broadest grouping you query to the most specific. For example:
Within CUSTOMER#42, a prefix of ORDER# selects orders. A prefix of ORDER#2026-10- selects October orders. A prefix of ADDRESS# selects addresses. Each is one Query access pattern, with pagination if necessary.
You cannot skip the beginning of the String to query an embedded order ID efficiently. If callers know 100 but do not know the customer or date, provide another lookup path, such as a GSI keyed by order ID. DynamoDB does not parse separators or create indexes for every embedded component.
Use one date format, timezone and precision throughout a key family. ISO-style dates sort chronologically when formatted consistently. For sequence numbers inside Strings, fixed-width padding avoids lexical order such as 1, 10, 2. Also escape separators or restrict component characters so different inputs cannot produce the same encoded key. The sort-key guide covers operators and ordering in detail.
Create a table with a composite primary key
The table schema, not merely the presence of two attributes in an item, defines a composite primary key. This AWS CLI v2 command creates the example myTable with String keys:
HASH and RANGE are API names for partition key and sort key. Non-key fields such as email do not belong in AttributeDefinitions unless an index also uses them as keys.
The following JavaScript examples use AWS SDK v3. Reuse this setup for each snippet:
Create an item with a composite key
The condition prevents overwriting that exact customer profile. It does not prevent another item with the same partition key and a different sort key. Remove the condition only if replacing an existing full item is the intended behavior.
Query a composite-key collection
You can query using just the partition key even though the table has a composite primary key. This reads the whole customer collection, one page at a time:
To select only orders, use the following request instead. Populate order records from the earlier example table before expecting order results:
Use the same pagination loop for a complete order history. Query output is ordered by sort key within the selected partition-key value, not globally across customers.
Get or update one item
An exact read requires both key attributes:
An update uses the same key. The condition prevents unintentionally creating a new item when the profile is missing:
Key names and value types must match the schema. Omitting sk, supplying an extra non-key field in Key, or sending a Number where the schema expects a String can cause a key-schema validation error.
Delete an item by composite key
The DeleteItem API deletes one item, not the entire partition-key collection. This SDK v3 request removes the customer profile and returns its previous attributes:
The AWS CLI equivalent uses DynamoDB's typed JSON format:
In boto3, the table resource accepts ordinary Python values:
These are alternative ways to perform the same deletion. An unconditional delete of a missing item succeeds without old attributes. Add a condition when deletion depends on an expected version or status. To delete every item in a collection, query all pages and delete each returned full key, handling concurrent writes and retries according to the application's requirements. There is no wildcard sort key for DeleteItem; see the item deletion guide for the broader workflow.
Changing keys and planning growth
You cannot use UpdateItem to change pk or sk. Moving an item means creating it under a new key and deleting it under the old key. Where supported, a transaction can make that pair atomic; use conditions to avoid overwriting a destination or moving a stale source version. Changing the table's key schema itself requires a new table and migration.
A hierarchy also needs a growth plan. Customer collections can become uneven, and a steadily growing date suffix does not spread a hot customer's writes by itself. Tables with LSIs have a 10 GB item-collection limit including LSI entries. The partition-key guide covers traffic distribution and sharding.
Before choosing an encoding, write down the exact keys and conditions for each screen or API. Check both small and large customers, duplicates, date boundaries and deletions. Dynobase's data modeling tools can help map those access patterns to table and GSI keys.
Frequently Asked Questions
How do I store a composite key in DynamoDB?
Can I query using only the partition key on a composite-key table?
Can a DynamoDB composite primary key use three attributes?
Can multiple items share a composite key?
How do I delete a DynamoDB item with a composite key?
Dynobase is a Professional GUI Client for DynamoDB
Start your 7-day free trial today