Help us improve
Share bugs, ideas, or general feedback.
From dynamo-expert
Designs a DynamoDB single-table structure from a documented set of access patterns. Use when the user has an access patterns .md file (from dynamodb-access-patterns skill) and wants to design partition keys, sort keys, GSIs, composite keys, and map every access pattern to a concrete DynamoDB query operation. This is Step 2 of a 3-step pipeline: access patterns -> table design -> query interfaces.
npx claudepluginhub walis85300/marketplace --plugin dynamo-expertHow this skill is triggered — by the user, by Claude, or both
Slash command
/dynamo-expert:dynamodb-table-designThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill takes a formalized access patterns document and produces a complete DynamoDB single-table design. It maps every access pattern to a concrete DynamoDB operation with explicit key conditions.
Reviews DynamoDB table design for access patterns, partition keys, indexes, hot partitions, capacity, and cost. Use when DynamoDB correctness, latency, scaling, or cost depends on table design.
Expert guidance on distributed NoSQL databases (Cassandra, DynamoDB), emphasizing query-first modeling, single-table design, partition key strategy, and avoiding hot partitions.
Designs NoSQL data models for MongoDB, DynamoDB, Redis, and Cassandra using access patterns, embedding/referencing decisions, and denormalization trade-offs.
Share bugs, ideas, or general feedback.
This skill takes a formalized access patterns document and produces a complete DynamoDB single-table design. It maps every access pattern to a concrete DynamoDB operation with explicit key conditions.
.md file (from dynamodb-access-patterns or manually written) 1. Access Patterns --> [2. Table Design] --> 3. Query Interfaces
(dynamodb-access- (this skill) (dynamodb-query-
patterns) interfaces)
Input: Access patterns .md file
Output: Table design .md file consumed by dynamodb-query-interfaces
Before starting, read the access patterns file. If it doesn't exist or is incomplete, tell the user to run the dynamodb-access-patterns skill first.
If the user already has a table in production and wants to add entities, also read their existing table design file (if any) to understand current keys and GSIs.
Read the access patterns file and verify:
If anything is missing, ask the user to clarify before proceeding.
This is the core of single-table design. Analyze the access patterns to determine which entities should share a partition key.
Rules for grouping:
Entities fetched together in a multi-entity read MUST share a PK.
1:N relationships where the parent is always known go under the parent's PK.
PK = USER#userIdEntities accessed only by their own ID get their own PK.
PK = PRODUCT#productIdGlobal collections (list all, leaderboard) use a static PK.
PK = PRODUCTSN:N or deeply nested relationships use composite PKs.
PK = USER#userId#CART#cartIdPresent the proposed grouping to the user:
Based on your access patterns, here's how I'd group entities:
Item Collection 1: User scope
PK = USER#<userId>
Contains: User, Order, Balance, Preferences
Supports: AP-001, AP-002, AP-003, AP-005
Item Collection 2: Product catalog
PK = PRODUCTS
Contains: Product (catalog entries)
Supports: AP-006, AP-007
Item Collection 3: Product detail
PK = PRODUCT#<productId>
Contains: Product (full record), Review
Supports: AP-008, AP-009, AP-010
Does this grouping make sense? Any patterns I'm missing?
For each item type, define the PK and SK.
Key Design Principles:
Use # as the separator between key segments. This is the universal DynamoDB convention.
PK = ENTITY_PREFIX#identifier
SK = ENTITY_PREFIX#identifier
| Pattern | Format | Use Case |
|---|---|---|
| Entity-scoped | ENTITY#<id> | Self-lookup, entity owns its collection |
| Parent-scoped | PARENT#<parentId> | Children queried under a parent |
| Static collection | COLLECTION_NAME | Global lists, catalogs, leaderboards |
| Hierarchical | PARENT#<id>#CHILD#<childId> | Deep nesting (use sparingly) |
| Pattern | Format | Use Case |
|---|---|---|
| Same as PK | ENTITY#<id> | 1:1 self-referencing record |
| Child entity | CHILD_TYPE#<childId> | Items in a collection |
| Composite | TYPE#<sortField>#<uniqueId> | Multi-field sorting |
| Metadata | METADATA or COUNTER | Singleton items in a collection |
| Timestamp-prefixed | TYPE#<ISO-timestamp>#<id> | Time-ordered collections |
If an access pattern needs sorting or range queries, the sort field MUST be encoded in the SK:
# Sort by date (newest first -- use ScanIndexForward=false)
SK = ORDER#2024-01-15T10:30:00Z#01HORDERID
# Sort by score (string-encoded numbers must be zero-padded)
SK = SCORE#000150#01HPLAYERID (score=150, padded to 6 digits)
# Sort by status + date (hierarchical sort)
SK = ORDER#SHIPPED#2024-01-15T10:30:00Z#01HORDERID
Zero-padding rule: When numbers are used in string sort keys, they MUST be zero-padded to a fixed width so lexicographic order matches numeric order. Decide the maximum expected value and pad accordingly.
Descending order trick: To sort descending without ScanIndexForward=false, invert the value:
SK = SCORE#<(MAX_SCORE - actualScore) zero-padded>#<id>
For each access pattern NOT covered by the table's PK/SK, determine if a GSI is needed.
You need a GSI when:
| Situation | Example |
|---|---|
| Query by a non-key attribute | "Find user by email" (table PK is userId) |
| Different sort order on same collection | "Orders by total" (table SK sorts by date) |
| Inverted relationship | "Find all orders containing product X" |
| Global sorted view | "Leaderboard sorted by score" |
GSI Design Rules:
Reuse GSIs aggressively. DynamoDB allows max 20 GSIs per table. Each GSI costs additional storage and write capacity. Design GSI keys to be overloaded across entity types when possible.
Name GSIs generically. Use GSI1, GSI2, GSI3 for overloaded indexes. Use descriptive names only for single-purpose indexes (e.g., email-index).
GSI key attributes follow the naming convention:
GSI1PK (String), GSI1SK (String)email as PK, createdAt as SK)Choose the right projection:
ALL -- projects all attributes (default, simplest, most expensive)KEYS_ONLY -- only key attributes (cheapest, requires table fetch for other attributes)INCLUDE -- specific attributes (middle ground)Sparse indexes are powerful. If only some items have the GSI attributes, only those items appear in the index. Use this to create filtered views.
Present GSI decisions to the user:
I need the following GSIs:
GSI1 (overloaded, String/String):
- User lookup by email: GSI1PK=EMAIL#<email>, GSI1SK=EMAIL#<email>
- Order leaderboard: GSI1PK=ORDERS, GSI1SK=ORDER#<total-inverted>#<orderId>
Projection: ALL
No additional GSIs needed. Total: 1 GSI.
Does this look right? Are there access patterns I should reconsider?
This is the accountability step. EVERY access pattern from the input file must be mapped to a concrete DynamoDB operation.
For each access pattern, define:
| Field | Description |
|---|---|
| AP ID | Reference to the access pattern |
| DynamoDB Operation | Query, GetItem, BatchGetItem, PutItem, TransactWriteItems, UpdateItem, DeleteItem |
| Table or GSI | Which index to use |
| PK Value | Exact partition key value (with placeholders) |
| SK Condition | =, begins_with, >, <, >=, <=, BETWEEN |
| SK Value(s) | The sort key value(s) |
| Additional Parameters | Limit, ScanIndexForward, FilterExpression, ProjectionExpression |
| Condition Expression | For writes: conditions that must be met |
Example:
AP-001: Get user by userId
Operation: Query
Table: Main
PK: USER#<userId>
SK: = USER#<userId>
Params: Limit=1
AP-002: List orders for user, newest first
Operation: Query
Table: Main
PK: USER#<userId>
SK: begins_with(ORDER#)
Params: ScanIndexForward=false, Limit=20, paginated
AP-010: Create order
Operation: TransactWriteItems
Items:
1. Put: PK=USER#<userId>, SK=ORDER#<timestamp>#<orderId> (Condition: attribute_not_exists(pk))
2. Put: PK=ORDER#<orderId>, SK=ORDER#<orderId> (Condition: attribute_not_exists(pk))
3. Update: PK=USER#<userId>, SK=ORDER_COUNT (SET count = count + 1)
Read reference/validation-checklist.md and run through every check with the user before finalizing.
Persist the output as a markdown file. Suggest docs/dynamodb/table-design.md or alongside the access patterns file.
Read reference/output-template.md for the exact file structure to use.
Read reference/design-patterns.md for a catalog of reusable single-table design patterns. Reference these when making key design decisions and present relevant patterns to the user.
PRODUCTS will receive heavy traffic, discuss sharding strategies with the user..md file.Once the table design file is complete, tell the user:
Table design is documented at [file path].
The next step is to generate the query interface -- method signatures
for every access pattern, ready to be implemented in your language of choice.
To continue, use the `dynamodb-query-interfaces` skill with this file as input.