Skip to main content

Storage Composition

MastraStorage can compose storage domains from different adapters. Use it when you need different databases for different purposes. For example, use LibSQL for memory and PostgreSQL for workflows.

Installation
Direct link to Installation

MastraStorage is included in @mastra/core:

npm install @mastra/core@beta

You'll also need to install the storage adapters you want to compose:

npm install @mastra/pg@beta @mastra/libsql@beta

Storage Domains
Direct link to Storage Domains

Mastra organizes storage into five specialized domains, each handling a specific type of data. Each domain can be backed by a different storage adapter, and domain classes are exported from each storage package.

DomainDescription
memoryConversation persistence for agents. Stores threads (conversation sessions), messages, resources (user identities), and working memory (persistent context across conversations).
workflowsWorkflow execution state. When workflows suspend for human input, external events, or scheduled resumption, their state is persisted here to enable resumption after server restarts.
scoresEvaluation results from Mastra's evals system. Scores and metrics are persisted here for analysis and comparison over time.
observabilityTelemetry data including traces and spans. Agent interactions, tool calls, and LLM requests generate spans collected into traces for debugging and performance analysis.
agentsAgent configurations for stored agents. Enables agents to be defined and updated at runtime without code deployments.

Usage
Direct link to Usage

Basic composition
Direct link to Basic composition

Import domain classes directly from each store package and compose them:

import { MastraStorage } from "@mastra/core/storage";
import { WorkflowsPG, ScoresPG } from "@mastra/pg";
import { MemoryLibSQL } from "@mastra/libsql";
import { Mastra } from "@mastra/core";

const mastra = new Mastra({
storage: new MastraStorage({
id: "composite",
domains: {
memory: new MemoryLibSQL({ url: "file:./local.db" }),
workflows: new WorkflowsPG({ connectionString: process.env.DATABASE_URL }),
scores: new ScoresPG({ connectionString: process.env.DATABASE_URL }),
},
}),
});

With a default storage
Direct link to With a default storage

Use default to specify a fallback storage, then override specific domains:

import { MastraStorage } from "@mastra/core/storage";
import { PostgresStore } from "@mastra/pg";
import { MemoryLibSQL } from "@mastra/libsql";
import { Mastra } from "@mastra/core";

const pgStore = new PostgresStore({
id: "pg",
connectionString: process.env.DATABASE_URL,
});

const mastra = new Mastra({
storage: new MastraStorage({
id: "composite",
default: pgStore,
domains: {
memory: new MemoryLibSQL({ url: "file:./local.db" }),
},
}),
});

Options
Direct link to Options

id:

string
Unique identifier for this storage instance.

default?:

MastraStorage
Default storage adapter. Domains not explicitly specified in `domains` will use this storage's domains as fallbacks.

domains?:

object
Individual domain overrides. Each domain can come from a different storage adapter. These take precedence over the default storage.

domains.memory?:

MemoryStorage
Storage for threads, messages, and resources.

domains.workflows?:

WorkflowsStorage
Storage for workflow snapshots.

domains.scores?:

ScoresStorage
Storage for evaluation scores.

domains.observability?:

ObservabilityStorage
Storage for traces and spans.

domains.agents?:

AgentsStorage
Storage for stored agent configurations.

disableInit?:

boolean
When true, automatic initialization is disabled. You must call init() explicitly.

Initialization
Direct link to Initialization

MastraStorage initializes each configured domain independently. When passed to the Mastra class, init() is called automatically:

import { MastraStorage } from "@mastra/core/storage";
import { MemoryPG, WorkflowsPG, ScoresPG } from "@mastra/pg";
import { Mastra } from "@mastra/core";

const storage = new MastraStorage({
id: "composite",
domains: {
memory: new MemoryPG({ connectionString: process.env.DATABASE_URL }),
workflows: new WorkflowsPG({ connectionString: process.env.DATABASE_URL }),
scores: new ScoresPG({ connectionString: process.env.DATABASE_URL }),
},
});

const mastra = new Mastra({
storage, // init() called automatically
});

If using storage directly, call init() explicitly:

import { MastraStorage } from "@mastra/core/storage";
import { MemoryPG } from "@mastra/pg";

const storage = new MastraStorage({
id: "composite",
domains: {
memory: new MemoryPG({ connectionString: process.env.DATABASE_URL }),
},
});

await storage.init();

// Access domain-specific stores via getStore()
const memoryStore = await storage.getStore("memory");
const thread = await memoryStore?.getThreadById({ threadId: "..." });

Use Cases
Direct link to Use Cases

Separate databases for different workloads
Direct link to Separate databases for different workloads

Use a local database for development while keeping production data in a managed service:

import { MastraStorage } from "@mastra/core/storage";
import { MemoryPG, WorkflowsPG, ScoresPG } from "@mastra/pg";
import { MemoryLibSQL } from "@mastra/libsql";

const storage = new MastraStorage({
id: "composite",
domains: {
// Use local SQLite for development, PostgreSQL for production
memory:
process.env.NODE_ENV === "development"
? new MemoryLibSQL({ url: "file:./dev.db" })
: new MemoryPG({ connectionString: process.env.DATABASE_URL }),
workflows: new WorkflowsPG({ connectionString: process.env.DATABASE_URL }),
scores: new ScoresPG({ connectionString: process.env.DATABASE_URL }),
},
});

Specialized storage for observability
Direct link to Specialized storage for observability

Use a time-series database for traces while keeping other data in PostgreSQL:

import { MastraStorage } from "@mastra/core/storage";
import { MemoryPG, WorkflowsPG, ScoresPG } from "@mastra/pg";
import { ObservabilityStorageClickhouse } from "@mastra/clickhouse";

const storage = new MastraStorage({
id: "composite",
domains: {
memory: new MemoryPG({ connectionString: process.env.DATABASE_URL }),
workflows: new WorkflowsPG({ connectionString: process.env.DATABASE_URL }),
scores: new ScoresPG({ connectionString: process.env.DATABASE_URL }),
observability: new ObservabilityStorageClickhouse({
url: process.env.CLICKHOUSE_URL,
username: process.env.CLICKHOUSE_USERNAME,
password: process.env.CLICKHOUSE_PASSWORD,
}),
},
});