저장
Storage API는 모든 방법에서 일관된 페이지 매김 및 이름 지정 패턴으로 표준화되었습니다.
데이터베이스 마이그레이션데이터베이스 마이그레이션에 대한 직접 링크
일반적인 마이그레이션 프로세스(예: Prisma Migrate, Drizzle Kit 또는 DBA 검토 프로세스)를 통해 이러한 SQL 마이그레이션을 실행하세요.
득점자 테이블 열 이름 바꾸기득점자 테이블 열 이름 바꾸기에 대한 직접 링크
mastra_scorers의 runtimeContext 열 이름이 requestContext로 변경되었습니다.
:::note[이 마이그레이션이 필요한 대상]
Evals/채점과 함께 @mastra/pg 또는 @mastra/libsql을 사용하며 runtimeContext 열에 기존 데이터가 있는 경우에만 필요합니다.
:::
:::중요[그것이 없으면 고장나는 것]
기존 점수 기록에는 요청 컨텍스트 데이터에 액세스할 수 없습니다.
:::
v1을 배포한 후(초기화 시 새 requestContext 열이 생성됨) 데이터를 복사하고 이전 열을 삭제하세요.
UPDATE mastra_scorers SET "requestContext" = "runtimeContext" WHERE "runtimeContext" IS NOT NULL;
ALTER TABLE mastra_scorers DROP COLUMN "runtimeContext";
중복 스팬 마이그레이션중복 스팬 마이그레이션에 대한 직접 링크
이전 버전의 Mastra에서 업그레이드하는 경우 mastra_spans 테이블에 중복된 (traceId, spanId) 항목이 있을 수 있습니다. V1은 데이터 무결성을 보장하기 위해 이러한 열에 고유 제약 조건을 추가하지만 중복 항목이 있으면 이 제약 조건을 추가할 수 없습니다.
:::note[이 마이그레이션이 필요한 사람]
v1 이전 Mastra 버전의 기존 범위 데이터가 있고 중복 키 위반 또는 제약 조건 생성 실패에 대한 오류가 발생한 경우에만 해당됩니다.
:::
:::중요[그것이 없으면 고장나는 것] 고유 제약 조건을 추가하려고 하면 스토리지 초기화가 실패하거나 "중복 키 값이 고유 제약 조건을 위반합니다"와 같은 오류가 표시될 수 있습니다. :::
옵션 1: CLI 사용(권장)옵션 1: CLI 사용(권장)에 대한 직접 링크
자동으로 스팬 중복을 제거하고 제약조건을 추가하는 마이그레이션 명령어를 실행합니다.
npx mastra migrate
CLI는 마이그레이션을 실행하기 전에 프로젝트를 번들링하고 구성된 스토리지에 연결합니다. 중복 항목을 제거할 때 가장 완전한 레코드(endTime 및 속성)를 유지합니다.
옵션 2: 수동 SQL(PostgreSQL)옵션 2: 수동 SQL(PostgreSQL)에 대한 직접 링크
마이그레이션을 수동으로 실행하려는 경우:
-- Remove duplicates, keeping the most complete record
DELETE FROM mastra_spans a USING mastra_spans b
WHERE a.ctid < b.ctid
AND a."traceId" = b."traceId"
AND a."spanId" = b."spanId";
-- Add the unique constraint
ALTER TABLE mastra_spans ADD CONSTRAINT mastra_spans_trace_span_unique UNIQUE ("traceId", "spanId");
옵션 3: 수동 마이그레이션(기타 데이터베이스)옵션 3: 수동 마이그레이션(기타 데이터베이스)에 대한 직접 링크
ClickHouse, LibSQL, MongoDB 또는 MSSQL의 경우 프로그래밍 방식 API를 사용합니다.
const storage = mastra.getStorage()
const observabilityStore = await storage.getStore('observability')
// Check if migration is needed
const status = await observabilityStore?.checkSpansMigrationStatus()
console.log(status)
// Run the migration
const result = await observabilityStore?.migrateSpans()
console.log(result)
JSON 열(TEXT → JSONB)JSON 열(TEXT → JSONB)에 대한 직접 링크
PostgreSQL에만 해당됩니다.그mastra_threads의 metadata 열과 mastra_workflow_snapshot의 snapshot 열이 TEXT에서 JSONB로 변경되었습니다.
:::참고[권장]
JSONB로 마이그레이션하면 기본 PostgreSQL JSON 연산자와 GIN 인덱싱이 활성화되어 JSON 필드에 대한 쿼리 성능이 향상됩니다.
:::
ALTER TABLE mastra_threads
ALTER COLUMN metadata TYPE jsonb
USING metadata::jsonb;
ALTER TABLE mastra_workflow_snapshot
ALTER COLUMN snapshot TYPE jsonb
USING snapshot::jsonb;
추가됨추가됨에 대한 직접 링크
저장 구성MastraCompositeStorestorage-composition-in-mastracompositestore에 대한 직접 링크
MastraCompositeStore이제 다양한 어댑터에서 스토리지 도메인을 구성할 수 있습니다. 다양한 목적을 위해 다양한 데이터베이스가 필요한 경우 이를 사용하세요. 예를 들어 Memory 및 Workflow에는 PostgreSQL이 필요하지만 Observability에는 특수 데이터베이스가 필요합니다.
import { MastraCompositeStore } 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 MastraCompositeStore({
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 }),
},
}),
})
자세한 내용은 스토리지 컴포지션 레퍼런스를 참조하세요.
변경됨변경됨에 대한 직접 링크
MastraStorage다음으로 이름이 변경됨MastraCompositeStoremastrastorage-renamed-to-mastracompositestore에 대한 직접 링크
여러 도메인을 서로 다른 기본 스토어로 라우팅하는 복합 스토리지 구현이라는 역할을 더 잘 나타내도록 MastraStorage 클래스의 이름이 MastraCompositeStore로 변경되었습니다. 이를 통해 일반적인 "Mastra Storage" 개념(Mastra 인스턴스의 storage 속성)과 혼동되는 것을 방지합니다.
이전 MastraStorage 이름은 하위 호환성을 위해 더 이상 사용되지 않는 별칭으로 계속 제공되지만 향후 버전에서 제거될 예정입니다.
마이그레이션하려면 가져오기 및 인스턴스화를 업데이트하세요.
- import { MastraStorage } from "@mastra/core/storage";
+ import { MastraCompositeStore } from "@mastra/core/storage";
import { MemoryLibSQL } from "@mastra/libsql";
import { WorkflowsPG } from "@mastra/pg";
export const mastra = new Mastra({
- storage: new MastraStorage({
+ storage: new MastraCompositeStore({
id: "composite",
domains: {
memory: new MemoryLibSQL({ url: "file:./memory.db" }),
workflows: new WorkflowsPG({ connectionString: process.env.DATABASE_URL }),
},
}),
});
:::참고
PostgresStore 또는 LibSQLStore 같은 단일 스토어 구현을 직접 사용한다면 기존 구성을 유지하세요. 이 변경은 복합 스토리지에 MastraStorage를 명시적으로 사용하는 코드에만 영향을 줍니다.
:::
스토리지 인스턴스에 필수인 id 속성required-id-property-for-storage-instances에 대한 직접 링크
이제 스토리지 인스턴스에는 id 속성이 필요합니다. 이 고유 식별자는 Mastra 내에서 스토리지 인스턴스를 추적하고 관리하는 데 사용됩니다. id는 애플리케이션의 각 스토리지 인스턴스를 설명하는 고유한 문자열이어야 합니다.
마이그레이션하려면 스토리지 생성자에 id 필드를 추가하세요.
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,
});
페이지네이션을 offset/limit에서 page/perPage로 변경pagination-from-offsetlimit-to-pageperpage에 대한 직접 링크
이제 모든 페이지네이션 API는 페이지 기반 웹 페이지네이션에 맞춰 offset과 limit 대신 page와 perPage를 사용합니다.
마이그레이션하려면 모든 페이지네이션 매개변수를 offset/limit에서 page/perPage로 업데이트하세요. page는 0부터 시작합니다.
memoryStore.listMessages({
threadId: 'thread-123',
- offset: 0,
- limit: 20,
+ page: 0,
+ perPage: 20,
});
getMessagesPaginated에게listMessagesgetmessagespaginated-to-listmessages에 대한 직접 링크
getMessagesPaginated() 메서드가 listMessages()로 대체되었습니다. 새 메서드는 페이지네이션 없이 모든 레코드를 가져오는 perPage: false를 지원합니다. 이 변경은 list* 명명 규칙과 일치하며 모든 레코드를 가져올 때의 유연성을 높입니다.
마이그레이션하려면 메서드 이름을 바꾸고 페이지네이션 매개변수를 업데이트하세요. 이제 모든 레코드를 가져올 때 perPage: false를 사용할 수 있습니다.
+ 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,
+ });
:::tip[코드모드]
Mastra의 codemod CLI를 사용하여 코드를 자동으로 업데이트할 수 있습니다.
npx @mastra/codemod@latest v1/storage-get-messages-paginated .
:::
다음을 통한 도메인별 스토리지 액세스getStore()domain-specific-storage-access-via-getstore에 대한 직접 링크
이제 스토리지 작업은 스토리지 인스턴스에서 직접 액세스하는 대신 도메인별 저장소를 통해 액세스됩니다.
도메인에는 다음이 포함됩니다.
memory- 스레드, 메시지, 리소스workflows- Workflow 스냅샷scores- 평가점수observability- 추적 및 범위agents- 저장된 Agent 데이터
마이그레이션하려면 도메인 이름으로 getStore()를 호출한 다음 반환된 스토어에서 메서드를 호출하세요.
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에게listThreadsgetthreadsbyresourceid-to-listthreads에 대한 직접 링크
getThreadsByResourceId() 메서드가 listThreads()로 대체되었습니다. 새 메서드는 페이지네이션과 resourceId, metadata 또는 둘 모두를 기준으로 한 필터링을 지원합니다.
:::중요한
이전 getThreadsByResourceId()는 페이지네이션 없이 일치하는 모든 스레드를 반환했습니다. 새 listThreads()에는 페이지네이션 매개변수가 필요합니다. 모든 스레드를 가져오는 이전 동작을 유지하려면 perPage: false를 사용하세요.
:::
마이그레이션하려면 Memory 스토어와 페이지네이션 및 선택적 필터 객체를 지원하는 새 listThreads() 메서드를 사용하세요.
- const threads = await storage.getThreadsByResourceId({
- resourceId: 'res-123',
- });
+ const memoryStore = await storage.getStore('memory');
+
+ // Paginated (recommended for large datasets)
+ const result = await memoryStore?.listThreads({
+ filter: { resourceId: 'res-123' },
+ page: 0,
+ perPage: 20,
+ });
+ const threads = result?.threads;
+
+ // Or fetch all threads like before (use perPage: false)
+ const allResult = await memoryStore?.listThreads({
+ filter: { resourceId: 'res-123' },
+ perPage: false,
+ });
+ const allThreads = allResult?.threads;
새로운 방법은 다음도 지원합니다.
- 모든 스레드 나열(필터 생략)
- 메타데이터로만 필터링
- 결합된 리소스 ID + 메타데이터 필터
// List all threads
await memoryStore?.listThreads({ page: 0, perPage: 20 })
// Filter by metadata only
await memoryStore?.listThreads({
filter: { metadata: { status: 'active' } },
page: 0,
perPage: 20,
})
// Combined filter
await memoryStore?.listThreads({
filter: {
resourceId: 'user-123',
metadata: { category: 'support' },
},
page: 0,
perPage: 20,
})
:::tip[코드모드]
Mastra의 codemod CLI를 사용하여 코드를 자동으로 업데이트할 수 있습니다.
npx @mastra/codemod@latest v1/storage-list-threads-by-resource-to-list-threads .
:::
getWorkflowRuns에게listWorkflowRunsgetworkflowruns-to-listworkflowruns에 대한 직접 링크
getWorkflowRuns() 메서드의 이름이 listWorkflowRuns()로 변경되었습니다. 이 변경은 컬렉션을 반환하는 메서드에 list*를 사용하는 규칙과 일치합니다.
마이그레이션하려면 Workflow 저장소를 사용하고 메서드 호출 이름을 바꾸고 페이지 매김 매개 변수를 업데이트하세요.
- const runs = await storage.getWorkflowRuns({
+ const workflowStore = await storage.getStore('workflows');
+ const runs = await workflowStore?.listWorkflowRuns({
fromDate,
toDate,
+ page: 0,
+ perPage: 20,
});
:::tip[코드모드]
Mastra의 codemod CLI를 사용하여 코드를 자동으로 업데이트할 수 있습니다.
npx @mastra/codemod@latest v1/storage-list-workflow-runs .
:::
getMessagesById에게listMessagesByIdgetmessagesbyid-to-listmessagesbyid에 대한 직접 링크
getMessagesById() 메서드의 이름이 listMessagesById()로 변경되었습니다. 이 변경은 컬렉션을 반환하는 메서드에 list*를 사용하는 규칙과 일치합니다.
마이그레이션하려면 Memory 저장소를 사용하고 메서드 호출의 이름을 바꾸세요.
+ const memoryStore = await storage.getStore('memory');
- const result = await storage.getMessagesById({
+ const result = await memoryStore?.listMessagesById({
messageIds: ['msg-1', 'msg-2'],
});
:::tip[코드모드]
Mastra의 codemod CLI를 사용하여 코드를 자동으로 업데이트할 수 있습니다.
npx @mastra/codemod@latest v1/storage-list-messages-by-id .
:::
스토리지 getMessages 및 saveMessages 시그니처storage-getmessages-and-savemessages-signatures에 대한 직접 링크
getMessages() 및 saveMessages() 메서드의 시그니처와 반환 타입이 변경되었습니다. 형식 오버로드가 제거되었으며 이제 이 메서드들은 항상 MastraDBMessage를 사용합니다. 이 변경은 형식 변형을 제거하여 API를 단순화합니다.
마이그레이션하려면 Memory 저장소를 사용하고, 형식 매개변수를 제거하고, 일관된 반환 유형으로 작동하도록 코드를 업데이트하세요.
+ 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[]
위치 인수에서 명명된 인수까지 벡터 저장 API위치 인수에서 명명된 인수까지 벡터 저장 API에 대한 직접 링크
이제 모든 벡터 저장 메서드는 위치 인수 대신 인수 개체를 사용합니다. 이렇게 하면 호출 사이트에서 각 값의 목적을 볼 수 있으며 인수 순서에 의존하지 않고 메서드 시그니처를 발전시킬 수 있습니다.
마이그레이션하려면 인수 객체를 사용하도록 모든 벡터 저장소 메서드 호출을 업데이트하세요.
- 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,
+ });
벡터 저장 메소드 이름 변경벡터 저장 메소드 이름 변경에 대한 직접 링크
updateIndexById 및 deleteIndexById 메서드의 이름이 각각 updateVector와 deleteVector로 변경되었습니다. 새 이름은 이 메서드가 벡터를 대상으로 작동한다는 점을 명확히 나타냅니다.
마이그레이션하려면 메서드 이름을 바꾸고 인수 개체를 전달하세요.
- await vectorDB.updateIndexById(indexName, id, update);
- await vectorDB.deleteIndexById(indexName, id);
+ await vectorDB.updateVector({ indexName, id, update });
+ await vectorDB.deleteVector({ indexName, id });
연결 문자열에서 객체로의 PGVector 생성자연결 문자열에서 객체로의 PGVector 생성자에 대한 직접 링크
이제 PGVector 생성자에는 연결 문자열 대신 객체 매개변수가 필요합니다. 이 변경으로 모든 스토리지 어댑터에 걸쳐 더욱 일관된 API가 제공됩니다.
마이그레이션하려면 연결 문자열을 개체 속성으로 전달합니다.
- const pgVector = new PgVector(process.env.POSTGRES_CONNECTION_STRING!);
+ const pgVector = new PgVector({
+ connectionString: process.env.POSTGRES_CONNECTION_STRING,
+ });
:::tip[코드모드]
Mastra의 codemod CLI를 사용하여 코드를 자동으로 업데이트할 수 있습니다.
npx @mastra/codemod@latest v1/vector-pg-constructor .
:::
PGVector: defineIndex에서 buildIndex로pgvector-defineindex-to-buildindex에 대한 직접 링크
defineIndex() 메서드가 제거되고 buildIndex()로 대체되었습니다. 새 이름은 이 메서드가 인덱스를 빌드한다는 점을 명확히 나타냅니다.
마이그레이션하려면 메서드 이름을 바꾸고 인수 개체를 전달하세요.
- await vectorDB.defineIndex(indexName, 'cosine', { type: 'flat' });
+ await vectorDB.buildIndex({
+ indexName: indexName,
+ metric: 'cosine',
+ indexConfig: { type: 'flat' },
+ });
PostgresStore: schema에서 schemaName으로postgresstore-schema-to-schemaname에 대한 직접 링크
PostgresStore 생성자의 schema 매개변수 이름이 schemaName으로 변경되었습니다. 새 이름은 해당 값이 데이터베이스 스키마의 이름임을 명확히 나타냅니다.
마이그레이션하려면 매개변수 이름을 바꾸세요.
const pgStore = new PostgresStore({
connectionString: process.env.POSTGRES_CONNECTION_STRING,
- schema: customSchema,
+ schemaName: customSchema,
});
:::tip[코드모드]
Mastra의 codemod CLI를 사용하여 코드를 자동으로 업데이트할 수 있습니다.
npx @mastra/codemod@latest v1/storage-postgres-schema-name .
:::
저장 방법에 점수를 매김listScoresBy* patternscore-storage-methods-to-listscoresby-pattern에 대한 직접 링크
점수 저장 API의 이름이 listScoresBy* 패턴을 따르도록 변경되었습니다. 이 변경으로 전반적인 API 명명 규칙과 일관성을 유지할 수 있습니다.
마이그레이션하려면 getScores를 listScoresByScorerId 및 관련 변형으로 변경하세요.
- const scores = await storage.getScores({ scorerName: 'helpfulness-scorer' });
+ const scores = await storage.listScoresByScorerId({
+ scorerId: 'helpfulness-scorer',
+ });
+ // Also available: listScoresByRunId, listScoresByEntityId, listScoresBySpan
제거됨제거됨에 대한 직접 링크
페이지가 매겨지지 않은 저장 기능페이지가 매겨지지 않은 저장 기능에 대한 직접 링크
페이지네이션되지 않은 저장 기능이 페이지네이션 버전으로 대체되어 제거되었습니다. 이제 모든 목록 작업에 페이지네이션이 적용되지만 perPage: false를 사용하면 모든 레코드를 가져올 수 있습니다. 이 변경으로 API 전반의 일관성을 유지하고 대규모 데이터 세트가 실수로 로드되는 것을 방지할 수 있습니다.
마이그레이션하려면 도메인 저장소를 통해 페이지를 매긴 방법을 사용하세요. 모든 레코드를 가져오려면 다음을 사용하세요.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그리고getTracesPaginatedgettraces-and-gettracespaginated에 대한 직접 링크
getTraces() 및 getTracesPaginated() 메서드가 스토리지에서 제거되었습니다. Trace에 액세스하려면 코어 스토리지 대신 Observability 패키지를 사용하세요.
마이그레이션하려면 대신 관측 가능성 스토리지 방법을 사용하세요.
- 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 도메인 테스트 유틸리티가 @internal/test-utils에서 제거되었습니다. 이 변경은 레거시 Evals 기능이 제거된 데 따른 것입니다.
마이그레이션하려면 전문 평가 테스트 유틸리티 대신 스토리지 API를 직접 사용하여 테스트하세요.
- import { createEvalsTests } from '@internal/test-utils/domains/evals';
- createEvalsTests({ storage });
+ // Use storage APIs directly for testing
MSSQL 스토리지의 TABLE_EVALSMSSQL 스토리지의 TABLE_EVALS에 대한 직접 링크
MSSQL 스토리지 구현에서 TABLE_EVALS 테이블이 제거되었습니다. 이 변경은 레거시 Evals 기능이 제거된 데 따른 것입니다.
평가 기능이 포함된 MSSQL 스토리지를 사용하고 있는 경우 다른 스토리지 어댑터로 마이그레이션하거나 평가 기능을 제거하세요.