Storage

Storage is the durable backing layer for Better Agent runtime data. Memory decides what conversation history to load. Storage decides where records are saved.

Better Agent only calls the storage methods. Your adapter decides how those records map to tables, collections, keys, or another backing store. The names below are the storage areas Better Agent passes to get, set, delete, and list.

Add storage

Configure storage at the app level.

import { betterAgent, createInMemoryStorage } from "@better-agent/core";

export const app = betterAgent({
  storage: createInMemoryStorage(),
  agents: [supportAgent],
});

createInMemoryStorage() is useful for local development and tests. Use a database adapter in production.

Storage areas

AreaUsed for
memoryThreadsThread metadata and access scope.
memoryMessagesStored conversation messages.
runsRun status, aborts, resume, and interrupted runs.
streamsStream lifecycle records.
streamEventsStream replay and resume.

Adapters

Production adapters live in the database docs. Database adapters document the schema shape they need. Drizzle and Prisma also include generators.

AdapterPackageGenerate command
Drizzle@better-agent/drizzlenpx @better-agent/drizzle generate
Prisma@better-agent/prismanpx @better-agent/prisma generate
Kysely@better-agent/kysely-
Redis@better-agent/redis-

See Drizzle, Kysely, Prisma, or Redis for setup.

Custom storage

Storage is a small interface. Implement it when you already have your own storage layer or want to map Better Agent records into your own schema.

import type { BetterAgentStorage } from "@better-agent/core";

const storage: BetterAgentStorage = {
  async get(table, id) {
    return db.get(table, id);
  },
  async set(table, id, value) {
    await db.set(table, id, value);
  },
  async delete(table, id) {
    await db.delete(table, id);
  },
  async list(table, query) {
    const items = await db.list(table, {
      where: query?.where,
      orderBy: query?.orderBy,
      limit: query?.take,
    });

    return { items };
  },
};

list supports where, orderBy, and take.

Composite storage

Use composite storage when different runtime data should go to different backends.

import { createCompositeStorage } from "@better-agent/core";

const storage = createCompositeStorage({
  domains: {
    memory: postgresStorage,
    streams: redisStorage,
  },
  default: postgresStorage,
});

Domains group related storage areas:

DomainAreas
memorymemoryThreads, memoryMessages
runsruns
streamsstreams, streamEvents

Route a single storage area when you need finer control.

const storage = createCompositeStorage({
  default: postgresStorage,
  tables: {
    streamEvents: redisStorage,
  },
});

Use omit to disable a storage domain.

const storage = createCompositeStorage({
  default: postgresStorage,
  omit: ["streams"],
});

Features that need an omitted area will behave as if that storage area is not configured.