Skip to main content

Storage

Storage APIs have been standardized with consistent pagination and naming patterns across all methods.

Added
Direct link to Added

Storage composition in MastraStorage
Direct link to Storage composition in MastraStorage

MastraStorage can now compose storage domains from different adapters. Use it when you need different databases for different purposes - for example, PostgreSQL for memory and workflows, but a specialized database for observability.

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

// Compose domains from different stores
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 }),
},
}),
});

See the Storage Composition reference for more details.

Changed
Direct link to Changed

Required id property for storage instances
Direct link to required-id-property-for-storage-instances

Storage instances now require an id property. This unique identifier is used for tracking and managing storage instances within Mastra. The id should be a descriptive, unique string for each storage instance in your application.

To migrate, add an id field to your storage constructor.

  const storage = new PostgresStore({
+ id: 'main-postgres-store',
connectionString: process.env.POSTGRES_CONNECTION_STRING,
schemaName: 'public',
});

const upstashStore = new UpstashStore({
+ id: 'upstash-cache-store',
url: process.env.UPSTASH_REDIS_REST_URL,
token: process.env.UPSTASH_REDIS_REST_TOKEN,
});

Pagination from offset/limit to page/perPage
Direct link to pagination-from-offsetlimit-to-pageperpage

All pagination APIs now use page and perPage instead of offset and limit. This change provides a more intuitive pagination model that aligns with common web pagination patterns.

To migrate, update all pagination parameters from offset/limit to page/perPage. Note that page is 0-indexed.

  memoryStore.listMessages({
threadId: 'thread-123',
- offset: 0,
- limit: 20,
+ page: 0,
+ perPage: 20,
});

getMessagesPaginated to listMessages
Direct link to getmessagespaginated-to-listmessages

The getMessagesPaginated() method has been replaced with listMessages(). The new method supports perPage: false to fetch all records without pagination. This change aligns with the list* naming convention and adds flexibility for fetching all records.

To migrate, rename the method and update pagination parameters. You can now use perPage: false to fetch all records.

+ const memoryStore = await storage.getStore('memory');
+
// Paginated
- const result = await storage.getMessagesPaginated({
+ const result = await memoryStore?.listMessages({
threadId: 'thread-123',
- offset: 0,
- limit: 20,
+ page: 0,
+ perPage: 20,
});

// Fetch all records (no pagination limit)
+ const allMessages = await memoryStore?.listMessages({
+ threadId: 'thread-123',
+ page: 0,
+ perPage: false,
+ });
Codemod

You can use Mastra's codemod CLI to update your code automatically:

npx @mastra/codemod@beta v1/storage-get-messages-paginated .

Domain-specific storage access via getStore()
Direct link to domain-specific-storage-access-via-getstore

Storage operations are now accessed through domain-specific stores instead of directly on the storage instance.

Domains include:

  • memory - Threads, messages, and resources
  • workflows - Workflow snapshots
  • scores - Evaluation scores
  • observability - Traces and spans
  • agents - Stored agent data

To migrate, call getStore() with the domain name, then call methods on the returned store.

  const storage = mastra.getStorage();

// Memory operations (threads, messages, resources)
- const thread = await storage.getThread({ threadId: '123' });
- await storage.saveThread({ thread });
+ const memoryStore = await storage.getStore('memory');
+ const thread = await memoryStore?.getThreadById({ threadId: '123' });
+ await memoryStore?.saveThread({ thread });

// Workflow operations (snapshots)
- const snapshot = await storage.loadWorkflowSnapshot({ runId, workflowName });
- await storage.persistWorkflowSnapshot({ runId, workflowName, snapshot });
+ const workflowStore = await storage.getStore('workflows');
+ const snapshot = await workflowStore?.loadWorkflowSnapshot({ runId, workflowName });
+ await workflowStore?.persistWorkflowSnapshot({ runId, workflowName, snapshot });

// Observability operations (traces, spans)
- const traces = await storage.listTraces({ page: 0, perPage: 20 });
+ const observabilityStore = await storage.getStore('observability');
+ const traces = await observabilityStore?.listTraces({ page: 0, perPage: 20 });

// Score operations (evaluations)
- const scores = await storage.listScoresByScorerId({ scorerId: 'helpfulness' });
+ const scoresStore = await storage.getStore('scores');
+ const scores = await scoresStore?.listScoresByScorerId({ scorerId: 'helpfulness' });

getThreadsByResourceId to listThreadsByResourceId
Direct link to getthreadsbyresourceid-to-listthreadsbyresourceid

The getThreadsByResourceId() method has been renamed to listThreadsByResourceId(). This change aligns with the convention that list* methods return collections.

To migrate, use the memory store and rename the method call with pagination parameters.

- const threads = await storage.getThreadsByResourceId({
+ const memoryStore = await storage.getStore('memory');
+ const threads = await memoryStore?.listThreadsByResourceId({
resourceId: 'res-123',
+ page: 0,
+ perPage: 20,
});
Codemod

You can use Mastra's codemod CLI to update your code automatically:

npx @mastra/codemod@beta v1/storage-get-threads-by-resource .

getWorkflowRuns to listWorkflowRuns
Direct link to getworkflowruns-to-listworkflowruns

The getWorkflowRuns() method has been renamed to listWorkflowRuns(). This change aligns with the convention that list* methods return collections.

To migrate, use the workflows stores, rename the method call and update pagination parameters.

- const runs = await storage.getWorkflowRuns({
+ const workflowStore = await storage.getStore('workflows');
+ const runs = await workflowStore?.listWorkflowRuns({
fromDate,
toDate,
+ page: 0,
+ perPage: 20,
});
Codemod

You can use Mastra's codemod CLI to update your code automatically:

npx @mastra/codemod@beta v1/storage-list-workflow-runs .

getMessagesById to listMessagesById
Direct link to getmessagesbyid-to-listmessagesbyid

The getMessagesById() method has been renamed to listMessagesById(). This change aligns with the convention that list* methods return collections.

To migrate, use the memory store and rename the method call.

+ const memoryStore = await storage.getStore('memory');
- const result = await storage.getMessagesById({
+ const result = await memoryStore?.listMessagesById({
messageIds: ['msg-1', 'msg-2'],
});
Codemod

You can use Mastra's codemod CLI to update your code automatically:

npx @mastra/codemod@beta v1/storage-list-messages-by-id .

Storage getMessages and saveMessages signatures
Direct link to storage-getmessages-and-savemessages-signatures

The getMessages() and saveMessages() methods have changed signatures and return types. Format overloads have been removed, and the methods now always work with MastraDBMessage. This change simplifies the API by removing format variations.

To migrate, use the memory store, remove format parameters, and update code to work with the consistent return type.

+ const memoryStore = await storage.getStore('memory');
+
// Always returns { messages: MastraDBMessage[] }
- const v1Messages = await storage.getMessages({ threadId, format: 'v1' });
- const v2Messages = await storage.getMessages({ threadId, format: 'v2' });
+ const result = await memoryStore?.getMessages({ threadId });
+ const messages = result?.messages; // MastraDBMessage[]

// SaveMessages always uses MastraDBMessage
- await storage.saveMessages({ messages: v1Messages, format: 'v1' });
- await storage.saveMessages({ messages: v2Messages, format: 'v2' });
+ const saveResult = await memoryStore?.saveMessages({ messages: mastraDBMessages });
+ const saved = saveResult?.messages; // MastraDBMessage[]

Vector store API from positional to named arguments
Direct link to Vector store API from positional to named arguments

All vector store methods now use named arguments instead of positional arguments. This change improves code readability and makes method signatures more maintainable.

To migrate, update all vector store method calls to use named arguments.

- await vectorDB.createIndex(indexName, 3, 'cosine');
+ await vectorDB.createIndex({
+ indexName: indexName,
+ dimension: 3,
+ metric: 'cosine',
+ });

- await vectorDB.upsert(indexName, [[1, 2, 3]], [{ test: 'data' }]);
+ await vectorDB.upsert({
+ indexName: indexName,
+ vectors: [[1, 2, 3]],
+ metadata: [{ test: 'data' }],
+ });

- await vectorDB.query(indexName, [1, 2, 3], 5);
+ await vectorDB.query({
+ indexName: indexName,
+ queryVector: [1, 2, 3],
+ topK: 5,
+ });

Vector store method renames
Direct link to Vector store method renames

The updateIndexById and deleteIndexById methods have been renamed to updateVector and deleteVector respectively. This change provides clearer naming that better describes the operations.

To migrate, rename the methods and use named arguments.

- await vectorDB.updateIndexById(indexName, id, update);
- await vectorDB.deleteIndexById(indexName, id);
+ await vectorDB.updateVector({ indexName, id, update });
+ await vectorDB.deleteVector({ indexName, id });

PGVector constructor from connection string to object
Direct link to PGVector constructor from connection string to object

The PGVector constructor now requires object parameters instead of a connection string. This change provides a more consistent API across all storage adapters.

To migrate, pass the connection string as an object property.

- const pgVector = new PgVector(process.env.POSTGRES_CONNECTION_STRING!);
+ const pgVector = new PgVector({
+ connectionString: process.env.POSTGRES_CONNECTION_STRING,
+ });
Codemod

You can use Mastra's codemod CLI to update your code automatically:

npx @mastra/codemod@beta v1/vector-pg-constructor .

PGVector defineIndex to buildIndex
Direct link to pgvector-defineindex-to-buildindex

The defineIndex() method has been removed in favor of buildIndex(). This change provides clearer naming for the index building operation.

To migrate, rename the method and use named arguments.

- await vectorDB.defineIndex(indexName, 'cosine', { type: 'flat' });
+ await vectorDB.buildIndex({
+ indexName: indexName,
+ metric: 'cosine',
+ indexConfig: { type: 'flat' },
+ });

PostgresStore schema to schemaName
Direct link to postgresstore-schema-to-schemaname

The schema parameter has been renamed to schemaName in the PostgresStore constructor. This change provides clearer naming to avoid confusion with database schema concepts.

To migrate, rename the parameter.

  const pgStore = new PostgresStore({
connectionString: process.env.POSTGRES_CONNECTION_STRING,
- schema: customSchema,
+ schemaName: customSchema,
});
Codemod

You can use Mastra's codemod CLI to update your code automatically:

npx @mastra/codemod@beta v1/storage-postgres-schema-name .

Score storage methods to listScoresBy* pattern
Direct link to score-storage-methods-to-listscoresby-pattern

Score storage APIs have been renamed to follow the listScoresBy* pattern. This change provides consistency with the broader API naming conventions.

To migrate, update method names from getScores to listScoresByScorerId and related variants.

- const scores = await storage.getScores({ scorerName: 'helpfulness-scorer' });
+ const scores = await storage.listScoresByScorerId({
+ scorerId: 'helpfulness-scorer',
+ });
+ // Also available: listScoresByRunId, listScoresByEntityId, listScoresBySpan

Removed
Direct link to Removed

Non-paginated storage functions
Direct link to Non-paginated storage functions

Non-paginated storage functions have been removed in favor of paginated versions. All list operations now use pagination, though you can fetch all records with perPage: false. This change provides consistency across the API and prevents accidental loading of large datasets.

To migrate, use paginated methods via domain stores. For fetching all records, use perPage: false.

- // Non-paginated direct access
- const messages = await storage.getMessages({ threadId });

+ // Use paginated methods via domain stores
+ const memoryStore = await storage.getStore('memory');
+ const result = await memoryStore?.listMessages({ threadId, page: 0, perPage: 20 });
+ // Or fetch all
+ const allMessages = await memoryStore?.listMessages({
+ threadId,
+ page: 0,
+ perPage: false,
+ });

getTraces and getTracesPaginated
Direct link to gettraces-and-gettracespaginated

The getTraces() and getTracesPaginated() methods have been removed from storage. Traces are now handled through the observability package rather than core storage. This change provides better separation of concerns between core storage and observability features.

To migrate, use observability storage methods instead.

- const traces = await storage.getTraces({ traceId: 'trace-123' });
- const paginated = await storage.getTracesPaginated({ page: 0, perPage: 20 });

+ // Use observability API for traces
+ import { initObservability } from '@mastra/observability';
+ const observability = initObservability({ config: { ... } });
+ // Access traces through observability API

Evals test utilities
Direct link to Evals test utilities

Evals domain test utilities have been removed from @internal/test-utils. This change reflects the removal of legacy evals functionality.

To migrate, use storage APIs directly for testing instead of specialized evals test utilities.

- import { createEvalsTests } from '@internal/test-utils/domains/evals';
- createEvalsTests({ storage });

+ // Use storage APIs directly for testing

TABLE_EVALS from MSSQL storage
Direct link to TABLE_EVALS from MSSQL storage

The TABLE_EVALS table has been removed from MSSQL storage implementations. This change reflects the removal of legacy evals functionality.

If you were using MSSQL storage with evals, migrate to a different storage adapter or remove evals functionality.