Storage overview
Mastra storage is organized into domains. Each domain owns a set of tables or collections. Depending on your adapter and configuration, you may use all domains or only a subset.
Storage domainsDirect link to Storage domains
MastraCompositeStore can route the following domain keys:
Not every storage adapter implements every domain. Composite storage lets you mix adapters per domain when the adapter packages export the corresponding domain classes.
| Domain | Description |
|---|---|
memory | Conversation persistence: messages, threads, and resources (including working memory). |
workflows | Workflow run snapshots used for suspend and resume. |
scores | Evaluation score records from eval runs. |
observability | Traces and spans used by observability exporters and Studio. |
datasets | Dataset records, versioned items, and dataset versions used by experiments. |
experiments | Experiment runs and per-item experiment results. |
The schema definitions below cover the built-in database-backed tables documented for memory, workflows, scores, and observability. Other domains, and non-database adapters, use implementation-specific storage structures.
Core schemaDirect link to Core schema
- Messages
- Threads
- Resources
- Workflows
- Evals
- Traces
Stores conversation messages and their metadata. Each message belongs to a thread and contains the actual content along with metadata about the sender role and message type.
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx){ format: 2, parts: [...] }user | assistantThe message content column contains a JSON object conforming to the MastraMessageContentV2 type, which is designed to align closely with the AI SDK UIMessage message shape.
type.Groups related messages together and associates them with a resource. Contains metadata about the conversation.
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx){
"category": "support",
"priority": 1
}Stores user-specific data for resource-scoped working memory. Each resource represents a user or entity, allowing working memory to persist across all conversation threads for that user.
{
"preferences": {
"language": "en",
"timezone": "UTC"
},
"tags": [
"premium",
"beta-user"
]
}When suspend() is called on a workflow, its state is saved in the following format. When resume() is called, that state is rehydrated.
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx){
"value": {
"currentState": "running"
},
"context": {
"stepResults": {},
"attempts": {},
"triggerData": {}
},
"activePaths": [],
"runId": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": 1648176000000
}Stores eval results from running metrics against agent outputs.
{
"score": 0.95,
"details": {
"reason": "Response accurately reflects source material",
"citations": [
"page 1",
"page 3"
]
}
}xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)Captures OpenTelemetry traces for monitoring and debugging.
workflow.myWorkflow.execute, http.request, database.query)@mastra/core, express, pg)INTERNAL (0, within process), CLIENT (1, outgoing calls), SERVER (2, incoming calls), PRODUCER (3, async job creation), CONSUMER (4, async job processing)code (UNSET=0, ERROR=1, OK=2) and optional message. Example:{
"code": 1,
"message": "HTTP request failed with status 500"
}{
"droppedAttributesCount": 2,
"droppedEventsCount": 1,
"instrumentationLibrary": "@opentelemetry/instrumentation-http"
}