Skip to main content

DuckDB storage

DuckDB is an embedded, in-process analytical database. The @mastra/duckdb package provides an OLAP-backed observability store for local development, suitable for traces, logs, metrics, scores, and feedback without running an external service.

For vector search, see the DuckDB vector store reference, which is a separate API in the same package.

When to use DuckDB
Direct link to When to use DuckDB

Local development of observability features. DuckDB is embedded and file-based, so it does not require a server and starts instantly. It supports the same observability signals as ClickHouse, which makes it useful for testing dashboards and trace exploration before deploying to a production backend.

DuckDB currently implements only the observability domain. Pair it with another storage adapter (such as LibSQL) for memory and workflows in a composite storage setup.

warning

DuckDB is for development and not recommended for production. It runs in-process, persists to a single local file, and does not work on platforms with ephemeral filesystems (such as Railway, Fly.io, Render, Heroku, or serverless containers). For production observability, use ClickHouse.

Installation
Direct link to Installation

npm install @mastra/duckdb@latest

Usage
Direct link to Usage

As the observability domain in a composite store
Direct link to As the observability domain in a composite store

This is the standard local-development setup. LibSQL handles the other domains, and DuckDB handles observability.

src/mastra/index.ts
import { Mastra } from '@mastra/core'
import { MastraCompositeStore } from '@mastra/core/storage'
import { LibSQLStore } from '@mastra/libsql'
import { DuckDBStore } from '@mastra/duckdb'
import { Observability, DefaultExporter } from '@mastra/observability'

export const mastra = new Mastra({
storage: new MastraCompositeStore({
id: 'composite-storage',
default: new LibSQLStore({
id: 'mastra-storage',
url: 'file:./mastra.db',
}),
domains: {
observability: new DuckDBStore().observability,
},
}),
observability: new Observability({
configs: {
default: {
serviceName: 'mastra',
exporters: [new DefaultExporter()],
},
},
}),
})

The .observability accessor returns the observability domain store directly. The equivalent generic form uses getStore(), which works for any composite-style storage adapter:

const observability = await new DuckDBStore().getStore('observability')

Standalone
Direct link to Standalone

When you need only observability storage outside the Mastra composite, instantiate DuckDBStore directly and access the observability domain:

import { DuckDBStore } from '@mastra/duckdb'

const duckdb = new DuckDBStore({ path: './traces.duckdb' })
const observability = duckdb.observability

await observability.init()

In-memory database
Direct link to In-memory database

Pass :memory: to use an ephemeral DuckDB instance. Data is lost when the process exits, which is appropriate for unit tests and short-lived scripts.

const duckdb = new DuckDBStore({ path: ':memory:' })

Configuration
Direct link to Configuration

DuckDBStore options
Direct link to duckdbstore-options

id?:

string
= 'duckdb'
Unique identifier for this storage instance.

path?:

string
= 'mastra.duckdb'
Path to the DuckDB database file. Use `:memory:` for an ephemeral in-memory database.

Lower-level types
Direct link to Lower-level types

@mastra/duckdb also exports DuckDBConnection for sharing a single underlying database across multiple Mastra storage instances, and the corresponding DuckDBStorageConfig type. Most applications will not need these directly.

Supported domains
Direct link to Supported domains

DuckDB currently implements one storage domain:

DomainSupported
observabilityYes
memoryNo
workflowsNo
scoresNo
agentsNo

For a full storage solution, compose DuckDBStore with an adapter that covers the missing domains (most commonly LibSQL for local development).

Initialization
Direct link to Initialization

When passed to Mastra through MastraCompositeStore, the observability domain initializes itself on first use. To run initialization explicitly outside of Mastra, call init() on the observability store:

import { DuckDBStore } from '@mastra/duckdb'

const duckdb = new DuckDBStore({ path: './traces.duckdb' })
await duckdb.observability.init()

Observability strategy
Direct link to Observability strategy

DuckDB supports the event-sourced strategy used by DefaultExporter, which buffers spans in memory and writes completed events in batches. This is appropriate for development-scale traffic. For high-volume production workloads, see DefaultExporter storage provider support.