OracleDB storage
The OracleDB storage provider stores Mastra application state in Oracle Database. It implements Mastra's composite storage interface, so one OracleStore instance can back memory, workflow snapshots, observability, scores, scorer definitions, MCP client metadata, and agent registry data.
InstallationDirect link to Installation
- npm
- pnpm
- Yarn
- Bun
npm install @mastra/oracledb@latest
pnpm add @mastra/oracledb@latest
yarn add @mastra/oracledb@latest
bun add @mastra/oracledb@latest
UsageDirect link to Usage
import { OracleStore } from '@mastra/oracledb'
const storage = new OracleStore({
id: 'oracle-storage',
user: process.env.ORACLE_DATABASE_USER,
password: process.env.ORACLE_DATABASE_PASSWORD,
connectString: process.env.ORACLE_DATABASE_CONNECT_STRING,
})
Use it with Mastra:
import { Mastra } from '@mastra/core/mastra'
export const mastra = new Mastra({
storage,
})
ParametersDirect link to Parameters
id:
user?:
pool or externalAuth.password?:
pool or externalAuth.connectString?:
pool.pool?:
store.close() is called.poolManager?:
OracleStore and OracleVector.schemaName?:
poolMin?:
poolMax?:
poolIncrement?:
configDir?:
tnsnames.ora.walletLocation?:
walletPassword?:
externalAuth?:
disableInit?:
messageBatchSize?:
executeMany call when saving messages. The operation still commits once at the transaction boundary.skipDefaultIndexes?:
indexes?:
migrationTableName?:
vectorRegistryTableName?:
OracleVector's registryTableName when that option is customized.Connection examplesDirect link to Connection examples
The basic username/password constructor is shown above. For Autonomous Database, add wallet options to the same constructor:
const storage = new OracleStore({
id: 'oracle-storage',
user: process.env.ORACLE_DATABASE_USER,
password: process.env.ORACLE_DATABASE_PASSWORD,
connectString: process.env.ORACLE_DATABASE_CONNECT_STRING,
walletLocation: process.env.ORACLE_DATABASE_WALLET_DIR,
walletPassword: process.env.ORACLE_DATABASE_WALLET_PASSWORD,
configDir: process.env.ORACLE_DATABASE_CONFIG_DIR,
})
For external authentication, set externalAuth: true and omit password. To reuse an existing oracledb.Pool, pass it as pool. Mastra uses it but doesn't close it.
OracleStore backs memory, workflow snapshots, observability, scores, scorer definitions, MCP client metadata, and agent registry data. When using the store outside a Mastra instance, call await storage.init() and access a domain with await storage.getStore('memory').
InitializationDirect link to Initialization
When you pass OracleStore to Mastra, init() is called automatically before storage operations run. If you use OracleStore directly, call init() before reading or writing:
await storage.init()
If initialization is disabled or skipped, storage operations require the Oracle tables and indexes to already exist.
OracleStore.init() runs repeatable migrations and records the result in the migration ledger table. The default ledger table is MASTRA_ORACLE_MIGRATIONS.
await storage.migrate()
const history = await storage.listMigrations()
Repeatable migrations are idempotent. They reconcile the tables and indexes owned by each storage domain on startup, which lets new domain indexes or compatible schema additions apply without changing application code.
Initialization also creates the provider's default indexes for common Mastra query paths. Use skipDefaultIndexes when indexes are managed separately, or pass indexes for custom Oracle indexes. Custom definitions support Oracle options such as bitmap, online, invisible, parallel, compress, noLogging, and reverse, as well as function-based expressions like JSON_VALUE(...).
Custom indexes are useful when your app repeatedly filters on JSON metadata or when database administrators (DBAs) want to test an index before the optimizer uses it:
const storage = new OracleStore({
id: 'oracle-storage',
user,
password,
connectString,
indexes: [
{
name: 'idx_messages_status',
table: 'mastra_messages',
columns: [
"JSON_VALUE(metadata, '$.status' RETURNING VARCHAR2(32) NULL ON ERROR)",
'thread_id',
],
online: true,
invisible: true,
},
],
})
Use invisible for staged rollout, then remove it after validating query plans. Use skipDefaultIndexes: true only when a DBA-managed indexing strategy replaces the defaults.
Use disableInit: true when schema changes are applied by a separate deployment step or by a database administrator.
Schema exportDirect link to Schema export
Use exportSchemas() to generate Oracle DDL without connecting to a database. This is useful when schema changes are reviewed or applied outside application startup.
import { exportSchemas } from '@mastra/oracledb'
const ddl = exportSchemas({
schemaName: 'MASTRA_APP',
domains: [
'memory',
'workflows',
'observability',
'scores',
'scorerDefinitions',
'mcpClients',
'agents',
],
})
console.log(ddl)
domains defaults to every supported domain, including vector, when omitted.
Operational notesDirect link to Operational notes
Use the same OraclePoolManager when OracleStore and OracleVector should share one Oracle connection lifecycle:
import { OracleStore, OracleVector } from '@mastra/oracledb'
const storage = new OracleStore({ id: 'oracle-storage', user, password, connectString })
const vector = new OracleVector({
id: 'oracle-vector',
poolManager: storage.getPoolManager(),
})
OracleStore exposes storage.db and await storage.getPool() for advanced use cases. When using these APIs directly, you're responsible for transaction boundaries and connection lifecycle.
JSON metadata, payloads, and snapshots are stored in native Oracle JSON columns and encoded server-side, so the rows are readable directly with standard Oracle JDBC tools such as DBeaver and SQL Developer.
Usage exampleDirect link to Usage example
Adding OracleDB memory to an agentDirect link to Adding OracleDB memory to an agent
import { Agent } from '@mastra/core/agent'
import { Memory } from '@mastra/memory'
import { OracleStore } from '@mastra/oracledb'
const storage = new OracleStore({
id: 'oracle-storage',
user: process.env.ORACLE_DATABASE_USER,
password: process.env.ORACLE_DATABASE_PASSWORD,
connectString: process.env.ORACLE_DATABASE_CONNECT_STRING,
})
export const oracleAgent = new Agent({
id: 'oracle-agent',
name: 'Oracle Agent',
instructions: 'You are an assistant with persistent OracleDB-backed memory.',
model: 'openai/gpt-5.6-sol',
memory: new Memory({ storage }),
})