# How to Integrate Custom Storage Solutions with OpenMAIC: A Complete Guide

> Integrate custom storage with OpenMAIC easily. Implement the StorageProvider interface and register your solution to leverage flexible, personalized data management. Learn how now.

- Repository: [MAIC/OpenMAIC](https://github.com/THU-MAIC/OpenMAIC)
- Tags: how-to-guide
- Published: 2026-09-05

---

**OpenMAIC is storage-agnostic and allows you to integrate any custom storage solution by implementing the `StorageProvider` interface defined in `packages/@openmaic/dsl/src/storage.ts` and registering your implementation in [`configs/storage.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/configs/storage.ts).**

OpenMAIC (THU-MAIC/OpenMAIC) is designed as a storage-agnostic platform that decouples persistence logic from application code through a clean abstraction layer. Rather than hard-coding dependencies on specific databases or storage backends, the platform exposes a minimal TypeScript interface that you can implement to connect IndexedDB, PostgreSQL, cloud object stores, or custom REST APIs. This guide explains how to integrate custom storage solutions with OpenMAIC using the provider pattern and runtime configuration system.

## Understanding the Storage Architecture

The OpenMAIC storage system relies on three core components that separate concerns between interface definition, runtime injection, and high-level consumption.

### The StorageProvider Interface

At `packages/@openmaic/dsl/src/storage.ts`, OpenMAIC declares the **storage contract** that all backends must satisfy. This TypeScript interface requires only four asynchronous methods:

```typescript
interface StorageProvider {
  getItem(key: string): Promise<string | null>;
  setItem(key: string, value: string): Promise<void>;
  removeItem(key: string): Promise<void>;
  clear?(): Promise<void>;
}

```

Because the contract is pure TypeScript with no external dependencies, you can implement it using virtually any key-value store, document database, or remote API.

### Runtime Configuration

The platform injects the concrete storage implementation at startup through [`configs/storage.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/configs/storage.ts). This file exports the `storage` instance that the entire application consumes:

```typescript
// configs/storage.ts
export const storage: StorageProvider = /* your implementation */;

```

By modifying this configuration—or supplying a custom config at startup—you tell OpenMAIC which provider to use for the current deployment without touching business logic.

### High-Level Storage Utilities

OpenMAIC provides utility wrappers like [`lib/utils/chat-storage.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/utils/chat-storage.ts) and [`lib/utils/stage-storage.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/utils/stage-storage.ts) that handle domain-specific persistence for chats, stages, and assets. These utilities delegate all I/O operations to the injected `StorageProvider`, meaning they automatically work with any backend that respects the interface.

## Implementing a Custom Storage Provider

To integrate a custom storage solution, create a class that implements the `StorageProvider` interface. Below is a complete example using **IndexedDB via Dexie** for browser-based persistence.

### Example: IndexedDB/Dexie Provider

Create a new file for your implementation:

```typescript
// my-custom-storage.ts
import type { StorageProvider } from '@/packages/@openmaic/dsl/src/storage';
import Dexie from 'dexie';

export class IndexedDBStorage implements StorageProvider {
  private db: Dexie;

  constructor() {
    this.db = new Dexie('openmaic-db');
    this.db.version(1).stores({
      kv: 'key,value',
    });
  }

  async getItem(key: string): Promise<string | null> {
    const record = await (this.db as any).kv.get({ key });
    return record ? record.value : null;
  }

  async setItem(key: string, value: string): Promise<void> {
    await (this.db as any).kv.put({ key, value });
  }

  async removeItem(key: string): Promise<void> {
    await (this.db as any).kv.delete(key);
  }

  async clear(): Promise<void> {
    await (this.db as any).kv.clear();
  }
}

```

Your class only needs to provide the four methods; the rest of the OpenMAIC codebase will interact with your storage through this uniform contract.

## Registering Your Custom Storage with OpenMAIC

After implementing the interface, wire your provider into the runtime by updating the central configuration file.

### Wiring into configs/storage.ts

Import your custom class and instantiate it in [`configs/storage.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/configs/storage.ts):

```typescript
// configs/storage.ts
import { IndexedDBStorage } from '@/my-custom-storage';
import type { StorageProvider } from '@/packages/@openmaic/dsl/src/storage';

export const storage: StorageProvider = new IndexedDBStorage();

```

Now every component that calls [`chat-storage.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/chat-storage.ts), [`stage-storage.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/stage-storage.ts), or any other utility will delegate to your `IndexedDBStorage` instance. No other code changes are required.

### Direct Usage in Application Code

If you need direct access to the storage—for example, in migration scripts or custom services—you can import the configured instance:

```typescript
import { storage } from '@/configs/storage';

await storage.setItem('session-id', 'abc-123');
const value = await storage.getItem('session-id'); // → 'abc-123'

```

## Advanced Example: Remote REST Storage

You can also implement the interface to delegate persistence to a remote HTTP API. This approach lets you use OpenMAIC with proprietary backends or serverless functions.

```typescript
// rest-storage.ts
import type { StorageProvider } from '@/packages/@openmaic/dsl/src/storage';

export class RestStorage implements StorageProvider {
  constructor(private baseUrl: string) {}

  async getItem(key: string): Promise<string | null> {
    const response = await fetch(`${this.baseUrl}/kv/${key}`);
    if (!response.ok) return null;
    return response.text();
  }

  async setItem(key: string, value: string): Promise<void> {
    await fetch(`${this.baseUrl}/kv/${key}`, {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ value }),
    });
  }

  async removeItem(key: string): Promise<void> {
    await fetch(`${this.baseUrl}/kv/${key}`, { method: 'DELETE' });
  }
}

```

Register `new RestStorage('https://api.example.com')` in [`configs/storage.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/configs/storage.ts), and OpenMAIC will persist all session data, chat history, and assets to your custom REST endpoint.

## Summary

- **Implement the interface**: Create a class that satisfies the `StorageProvider` contract from `packages/@openmaic/dsl/src/storage.ts` with `getItem`, `setItem`, `removeItem`, and optionally `clear`.
- **Configure the runtime**: Export your instance from [`configs/storage.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/configs/storage.ts) to inject it into the OpenMAIC server-side runtime.
- **Leverage existing utilities**: High-level helpers like [`lib/utils/chat-storage.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/utils/chat-storage.ts) work transparently with your custom backend without modification.
- **Support any backend**: Because the interface requires only basic key-value operations, you can integrate IndexedDB, PostgreSQL, Redis, S3, or custom REST APIs.

## Frequently Asked Questions

### What methods must a custom StorageProvider implement?

According to the source code in `packages/@openmaic/dsl/src/storage.ts`, you must implement three required methods: `getItem(key: string)`, `setItem(key: string, value: string)`, and `removeItem(key: string)`. The `clear()` method is optional. All methods return `Promise` objects since OpenMAIC expects asynchronous storage operations.

### Can I use OpenMAIC with cloud storage services like S3?

Yes. You can integrate AWS S3, Google Cloud Storage, or Azure Blob Storage by implementing the `StorageProvider` interface using the respective cloud SDKs. Map `getItem` to download operations, `setItem` to uploads, and `removeItem` to delete operations. Register your cloud-backed provider in [`configs/storage.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/configs/storage.ts) just like any other implementation.

### Where do I configure which storage provider OpenMAIC uses?

You specify the active storage implementation in [`configs/storage.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/configs/storage.ts). This file serves as the central registry where you import your custom class, instantiate it, and export it as the `storage` object. The OpenMAIC runtime imports this export and passes it to all persistence utilities throughout the application.

### Do I need to modify chat-storage.ts or stage-storage.ts to use custom storage?

No. Files like [`lib/utils/chat-storage.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/utils/chat-storage.ts) and [`lib/utils/stage-storage.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/utils/stage-storage.ts) are designed to consume the abstract `StorageProvider` interface rather than concrete implementations. They import the storage instance from [`configs/storage.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/configs/storage.ts) and delegate all read/write operations to it. This design ensures that switching storage backends requires changes only to the configuration file, not to domain-specific storage logic.