Skip to main content
Mastra provides a flexible storage system with pluggable backends for persisting agent state, workflow runs, memory threads, and other data.

Storage Architecture

Mastra’s storage system is built around composable adapters:

Quick Start

Configure storage in your Mastra instance:
import { Mastra } from '@mastra/core';
import { PgStorage } from '@mastra/pg';

const mastra = new Mastra({
  storage: new PgStorage({
    connectionString: process.env.DATABASE_URL,
  }),
});

Storage Domains

Mastra storage is organized into domains:

Memory

Store conversation threads and messages:
const memory = mastra.getStorage().memory;

// Save messages
await memory.saveMessages(threadId, [
  { role: 'user', content: 'Hello' },
  { role: 'assistant', content: 'Hi there!' },
]);

// Get thread history
const messages = await memory.getMessages({ threadId });

Workflows

Persist workflow runs and state:
const workflows = mastra.getStorage().workflows;

// Create workflow run
await workflows.createRun({
  workflowId: 'process-data',
  runId: 'run-123',
  status: 'pending',
});

// Update run status
await workflows.updateRunStatus(runId, 'completed');

Agents

Store agent configurations and state:
const agents = mastra.getStorage().agents;

// Save agent configuration
await agents.saveAgent({
  id: 'assistant',
  name: 'Customer Support',
  instructions: 'Help customers',
  model: 'openai/gpt-4',
});

Observability

Track tool calls, events, and metrics:
const observability = mastra.getStorage().observability;

// Log tool execution
await observability.logToolCall({
  toolName: 'get-weather',
  input: { location: 'NYC' },
  output: { temperature: 72 },
  duration: 150,
});

Scores

Store evaluation scores and metrics:
const scores = mastra.getStorage().scores;

// Save evaluation score
await scores.saveScore({
  runId: 'run-123',
  metric: 'accuracy',
  value: 0.95,
});

Pluggable Backends

Swap storage backends without changing application code:
// PostgreSQL
import { PgStorage } from '@mastra/pg';
const storage = new PgStorage({ 
  connectionString: process.env.DATABASE_URL 
});

// MongoDB
import { MongoStorage } from '@mastra/mongodb';
const storage = new MongoStorage({ 
  uri: process.env.MONGODB_URI 
});

// LibSQL (Turso)
import { LibSQLStorage } from '@mastra/libsql';
const storage = new LibSQLStorage({ 
  url: process.env.TURSO_URL,
  authToken: process.env.TURSO_TOKEN,
});

Composite Storage

Mix and match backends for different domains:
import { MastraCompositeStore } from '@mastra/core/storage';
import { PgStorage } from '@mastra/pg';
import { MongoStorage } from '@mastra/mongodb';

const storage = new MastraCompositeStore({
  memory: new PgStorage({ /* ... */ }).memory,
  workflows: new MongoStorage({ /* ... */ }).workflows,
  agents: new PgStorage({ /* ... */ }).agents,
  // ... other domains
});

const mastra = new Mastra({ storage });

Schema Management

Most SQL adapters provide schema export utilities:
import { exportSchemas } from '@mastra/pg';

// Export complete schema
const ddl = exportSchemas('mastra');
fs.writeFileSync('schema.sql', ddl);

// Or let the adapter create tables automatically
const storage = new PgStorage({
  connectionString: process.env.DATABASE_URL,
  // Tables will be created on first use
});

Vector Storage

Vector stores are used for semantic search and RAG:
import { PineconeVector } from '@mastra/pinecone';

const vectorStore = new PineconeVector({
  id: 'embeddings',
  apiKey: process.env.PINECONE_API_KEY,
});

// Create index
await vectorStore.createIndex({
  name: 'documents',
  dimension: 1536,
  metric: 'cosine',
});

// Upsert vectors
await vectorStore.upsert({
  indexName: 'documents',
  vectors: [
    {
      id: 'doc-1',
      values: embedding,
      metadata: { title: 'Getting Started' },
    },
  ],
});

// Query vectors
const results = await vectorStore.query({
  indexName: 'documents',
  vector: queryEmbedding,
  topK: 5,
});

Storage Configuration

Common configuration patterns:

Connection Pooling

const storage = new PgStorage({
  connectionString: process.env.DATABASE_URL,
  max: 20,              // Max connections
  idleTimeoutMillis: 30000,  // Idle timeout
});

Schema Namespacing

const storage = new PgStorage({
  connectionString: process.env.DATABASE_URL,
  schemaName: 'app_mastra',  // Custom schema name
});

Read Replicas

const storage = new PgStorage({
  primary: process.env.DATABASE_URL,
  replicas: [
    process.env.READ_REPLICA_1,
    process.env.READ_REPLICA_2,
  ],
});

Transaction Support

Some adapters support transactions:
const storage = new PgStorage({ /* ... */ });

await storage.transaction(async (tx) => {
  await tx.memory.saveMessages(threadId, messages);
  await tx.workflows.updateRunStatus(runId, 'completed');
  // Both operations succeed or both fail
});

Error Handling

Handle storage errors gracefully:
import { MastraError } from '@mastra/core/error';

try {
  await storage.memory.saveMessages(threadId, messages);
} catch (error) {
  if (error instanceof MastraError) {
    console.error('Storage error:', error.toJSON());
  }
  // Handle error
}

Performance Considerations

Use connection pooling for SQL databases to reuse connections and improve performance
Create indexes on frequently queried fields like threadId, workflowId, and timestamps
Batch multiple operations when possible to reduce round trips
Consider adding a cache layer (Redis, Upstash) for hot data paths

Migration Between Adapters

Switch storage backends:
import { PgStorage } from '@mastra/pg';
import { MongoStorage } from '@mastra/mongodb';

// Source storage
const source = new PgStorage({ /* ... */ });

// Target storage
const target = new MongoStorage({ /* ... */ });

// Migrate data
const threads = await source.memory.getThreads();
for (const thread of threads) {
  const messages = await source.memory.getMessages({ threadId: thread.id });
  await target.memory.saveMessages(thread.id, messages);
}

Next Steps

Storage Adapters

Explore available storage backends

Vector Stores

Learn about vector storage for RAG

Build docs developers (and LLMs) love