docs/src/content/en/reference/storage/dynamodb.mdx
The DynamoDB storage implementation provides a scalable and performant NoSQL database solution for Mastra, leveraging a single-table design pattern with ElectroDB.
:::warning[Observability Not Supported]
DynamoDB storage doesn't support the observability domain. Traces from the DefaultExporter can't be persisted to DynamoDB, and Mastra Studio's observability features won't work with DynamoDB as your only storage provider. To enable observability, use composite storage to route observability data to a supported provider like ClickHouse or PostgreSQL.
:::
:::warning[Item Size Limit] DynamoDB enforces a 400 KB maximum item size. This limit can be exceeded when storing messages with base64-encoded attachments such as images. See Handling large attachments for workarounds including uploading attachments to external storage. :::
npm install @mastra/dynamodb@latest
Before using this package, you must create a DynamoDB table with a specific structure, including primary keys and Global Secondary Indexes (GSIs). This adapter expects the DynamoDB table and its GSIs to be provisioned externally.
Detailed instructions for setting up the table using AWS CloudFormation or AWS CDK are available in TABLE_SETUP.md. Please ensure your table is configured according to those instructions before proceeding.
import { Memory } from '@mastra/memory'
import { DynamoDBStore } from '@mastra/dynamodb'
// Initialize the DynamoDB storage
const storage = new DynamoDBStore({
id: 'dynamodb', // Unique identifier for this storage instance
config: {
tableName: 'mastra-single-table', // Name of your DynamoDB table
region: 'us-east-1', // Optional: AWS region, defaults to 'us-east-1'
// endpoint: "http://localhost:8000", // Optional: For local DynamoDB
// credentials: { accessKeyId: "YOUR_ACCESS_KEY", secretAccessKey: "YOUR_SECRET_KEY" } // Optional
},
})
// Example: Initialize Memory with DynamoDB storage
const memory = new Memory({
storage,
options: {
lastMessages: 10,
},
})
For local development, you can use DynamoDB Local.
Run DynamoDB Local (e.g., using Docker):
docker run -p 8000:8000 amazon/dynamodb-local
Configure DynamoDBStore to use the local endpoint:
import { DynamoDBStore } from '@mastra/dynamodb'
const storage = new DynamoDBStore({
id: 'dynamodb-local',
config: {
tableName: 'mastra-single-table', // Ensure this table is created in your local DynamoDB
region: 'localhost', // Can be any string for local, 'localhost' is common
endpoint: 'http://localhost:8000',
// For DynamoDB Local, credentials are not typically required unless configured.
// If you've configured local credentials:
// credentials: { accessKeyId: "fakeMyKeyId", secretAccessKey: "fakeSecretAccessKey" }
},
})
You will still need to create the table and GSIs in your local DynamoDB instance, for example, using the AWS CLI pointed to your local endpoint.
<PropertiesTable
content={[
{
name: 'id',
type: 'string',
description: 'Unique identifier for this storage instance.',
isOptional: false,
},
{
name: 'config.tableName',
type: 'string',
description: 'The name of your DynamoDB table.',
isOptional: false,
},
{
name: 'config.region',
type: 'string',
description: "AWS region. Defaults to 'us-east-1'. For local development, can be set to 'localhost' or similar.",
isOptional: true,
},
{
name: 'config.endpoint',
type: 'string',
description: "Custom endpoint for DynamoDB (e.g., 'http://localhost:8000' for local development).",
isOptional: true,
},
{
name: 'config.credentials',
type: 'object',
description:
'AWS credentials object with accessKeyId and secretAccessKey. If not provided, the AWS SDK will attempt to source credentials from environment variables, IAM roles (e.g., for EC2/Lambda), or the shared AWS credentials file.',
isOptional: true,
},
{
name: 'config.ttl',
type: 'object',
description:
"TTL (Time To Live) configuration for automatic data expiration. Configure per entity type: thread, message, trace, eval, workflow_snapshot, resource, score. Each entity config includes: enabled (boolean), attributeName (string, default: 'ttl'), defaultTtlSeconds (number).",
isOptional: true,
},
]}
/>
DynamoDB TTL allows you to automatically delete items after a specified time period. This is useful for:
To use TTL, you must:
ttl)import { DynamoDBStore } from '@mastra/dynamodb'
const storage = new DynamoDBStore({
name: 'dynamodb',
config: {
tableName: 'mastra-single-table',
region: 'us-east-1',
ttl: {
// Messages expire after 30 days
message: {
enabled: true,
defaultTtlSeconds: 30 * 24 * 60 * 60, // 30 days
},
// Threads expire after 90 days
thread: {
enabled: true,
defaultTtlSeconds: 90 * 24 * 60 * 60, // 90 days
},
// Traces expire after 7 days with custom attribute name
trace: {
enabled: true,
attributeName: 'expiresAt', // Custom TTL attribute
defaultTtlSeconds: 7 * 24 * 60 * 60, // 7 days
},
// Workflow snapshots don't expire
workflow_snapshot: {
enabled: false,
},
},
},
})
TTL can be configured for these entity types:
| Entity | Description |
|---|---|
thread | Conversation threads |
message | Messages within threads |
trace | Observability traces |
eval | Evaluation results |
workflow_snapshot | Workflow state snapshots |
resource | User/resource data |
score | Scoring results |
Each entity type accepts the following configuration:
<PropertiesTable content={[ { name: 'enabled', type: 'boolean', description: 'Whether TTL is enabled for this entity type.', isOptional: false, }, { name: 'attributeName', type: 'string', description: "The DynamoDB attribute name to use for TTL. Must match the TTL attribute configured on your DynamoDB table. Defaults to 'ttl'.", isOptional: true, }, { name: 'defaultTtlSeconds', type: 'number', description: 'Default TTL in seconds from item creation time. Items will be automatically deleted by DynamoDB after this duration.', isOptional: true, }, ]} />
After configuring TTL in your code, you must enable TTL on the DynamoDB table itself:
Using AWS CLI:
aws dynamodb update-time-to-live \
--table-name mastra-single-table \
--time-to-live-specification "Enabled=true, AttributeName=ttl"
Using AWS Console:
ttl):::note
DynamoDB deletes expired items within 48 hours after expiration. Items remain queryable until actually deleted.
:::
The IAM role or user executing the code needs appropriate permissions to interact with the specified DynamoDB table and its indexes. Below is a sample policy. Replace ${YOUR_TABLE_NAME} with your actual table name and ${YOUR_AWS_REGION} and ${YOUR_AWS_ACCOUNT_ID} with appropriate values.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dynamodb:DescribeTable",
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:UpdateItem",
"dynamodb:DeleteItem",
"dynamodb:Query",
"dynamodb:Scan",
"dynamodb:BatchGetItem",
"dynamodb:BatchWriteItem"
],
"Resource": [
"arn:aws:dynamodb:${YOUR_AWS_REGION}:${YOUR_AWS_ACCOUNT_ID}:table/${YOUR_TABLE_NAME}",
"arn:aws:dynamodb:${YOUR_AWS_REGION}:${YOUR_AWS_ACCOUNT_ID}:table/${YOUR_TABLE_NAME}/index/*"
]
}
]
}
Before diving into the architectural details, keep these key points in mind when working with the DynamoDB storage adapter:
TABLE_SETUP.md) is important for understanding data retrieval and potential query patterns.This storage adapter utilizes a single-table design pattern leveraging ElectroDB, a common and recommended approach for DynamoDB. This differs architecturally from relational database adapters (like @mastra/pg or @mastra/libsql) that typically use multiple tables, each dedicated to a specific entity (threads, messages, etc.).
Key aspects of this approach:
MastraStorage interface as other adapters, ensuring it can be used interchangeably within the Mastra Memory component.Within the single DynamoDB table, different Mastra data entities (such as Threads, Messages, Traces, Evals, and Workflows) are managed and distinguished using ElectroDB. ElectroDB defines specific models for each entity type, which include unique key structures and attributes. This allows the adapter to store and retrieve diverse data types efficiently within the same table.
For example, a Thread item might have a primary key like THREAD#<threadId>, while a Message item belonging to that thread might use THREAD#<threadId> as a partition key and MESSAGE#<messageId> as a sort key. The Global Secondary Indexes (GSIs), detailed in TABLE_SETUP.md, are strategically designed to support common access patterns across these different entities, such as fetching all messages for a thread or querying traces associated with a particular workflow.
This implementation uses a single-table design pattern with ElectroDB, which offers several advantages within the context of DynamoDB: