# How to Set Up Server-Backed Persistence with PostgreSQL in OpenMAIC

> Learn to set up server-backed persistence with PostgreSQL in OpenMAIC. Configure a PostgreSQL container and the DATABASE_URL environment variable for seamless data management.

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

---

**Set up server-backed persistence with PostgreSQL in OpenMAIC by configuring a PostgreSQL 16 container, setting the `DATABASE_URL` environment variable, and allowing the storage runtime at `packages/@openmaic/storage/src/runtime/pg.ts` to automatically wire the PostgreSQL provider.**

OpenMAIC stores runtime state—whiteboard edits, chat histories, and assets—in a pluggable persistence layer. While the system defaults to an in-memory KV store for client-side fallback, enabling durable, server-backed persistence with PostgreSQL in OpenMAIC ensures data survives server restarts and supports multi-instance deployments.

## Understanding the OpenMAIC Persistence Architecture

The persistence stack consists of a generic interface and provider-specific implementations that are selected at runtime based on environment configuration.

### The PersistenceProvider Interface

The contract for all storage operations is defined in `packages/@openmaic/storage/src/runtime/types.ts`. This interface specifies methods for CRUD operations on sessions, assets, and whiteboard state. The PostgreSQL implementation in `packages/@openmaic/storage/src/runtime/pg.ts` satisfies this interface by creating a `node-postgres` pool and translating all calls into SQL statements.

### Auto-Detection Mechanism

When the OpenMAIC server starts, the storage layer checks for the presence of `process.env.DATABASE_URL`. If defined, the runtime automatically loads the PostgreSQL provider from `packages/@openmaic/storage/src/runtime/pg.ts` instead of the default in-memory store. This selection happens inside `createPersistence()`, the factory function exported by the storage package.

## Configuring the PostgreSQL Container

The repository includes a PostgreSQL service definition in [`docker-compose.yml`](https://github.com/THU-MAIC/OpenMAIC/blob/main/docker-compose.yml) that runs PostgreSQL 16 with persistent volume storage.

```yaml

# docker-compose.yml (excerpt)

services:
  postgres:
    image: postgres:16
    environment:
      POSTGRES_USER: openmaic
      POSTGRES_PASSWORD: openmaic-dev
      POSTGRES_DB: openmaic
    volumes:
      - openmaic-postgres:/var/lib/postgresql/data
    ports:
      - "5432:5432"

volumes:
  openmaic-postgres:

```

Start the database container:

```bash
docker compose up -d postgres

```

## Setting Up the Environment Variables

The storage runtime requires a `DATABASE_URL` environment variable to establish the connection. The format follows the standard PostgreSQL connection URI scheme:

```

postgres://<user>:<password>@<host>:<port>/<database>

```

Create a local environment file:

```bash
cp .env.example .env.local

```

Add the connection string to `.env.local`:

```dotenv

# .env.local

DATABASE_URL=postgres://openmaic:openmaic-dev@localhost:5432/openmaic

```

The `packages/@openmaic/storage/src/runtime/pg.ts` file reads this variable at startup to instantiate the connection pool.

## Initializing the Storage Runtime

No application code changes are required to switch storage backends. The entry point at `packages/@openmaic/storage/src/lib/storage/client.ts` exports `createPersistence()`, which automatically returns a PostgreSQL-backed instance when `DATABASE_URL` is present.

```typescript
// Application code (no changes needed for PG switch)
import { createPersistence } from '@openmaic/storage';

const persistence = createPersistence();
// Automatically uses PostgreSQL if DATABASE_URL is set, otherwise falls back to memory

```

## Verifying Persistence Functionality

Test the configuration by saving a whiteboard record and verifying it persists after a restart:

```typescript
// Save a whiteboard record
await persistence.whiteboard.save({
  sessionId: 'demo-session',
  recordId: 'record-001',
  data: { elements: [{ type: 'text', content: 'Hello' }] },
});

// After restarting the server, retrieve the record
const record = await persistence.whiteboard.load('demo-session', 'record-001');
console.log(record); // Contains the data saved before restart

```

## Optional: Running the Reference Persistence Server

For multi-node deployments where multiple OpenMAIC instances must share the same storage backend, run the reference server located at `packages/@openmaic/storage/src/server/index.ts`. This exposes the persistence layer over HTTP/JSON-RPC, allowing remote runtime instances to access the same PostgreSQL database.

```bash
pnpm exec ts-node packages/@openmaic/storage/src/server/index.ts

```

This server reads the same `DATABASE_URL` environment variable and listens for incoming persistence requests from other OpenMAIC nodes.

## Summary

- **PostgreSQL Container**: Define the service in [`docker-compose.yml`](https://github.com/THU-MAIC/OpenMAIC/blob/main/docker-compose.yml) using the official PostgreSQL 16 image with a named volume for data durability.
- **Environment Configuration**: Set `DATABASE_URL` to a valid PostgreSQL connection string; the storage runtime in `packages/@openmaic/storage/src/runtime/pg.ts` automatically detects this and creates a connection pool.
- **Zero-Code Migration**: Call `createPersistence()` from `packages/@openmaic/storage/src/lib/storage/client.ts`—the function automatically selects the PostgreSQL provider when the environment variable is present.
- **Reference Server**: For distributed deployments, use `packages/@openmaic/storage/src/server/index.ts` to expose persistence over HTTP.

## Frequently Asked Questions

### What is the correct format for the DATABASE_URL environment variable?

The URL must follow the PostgreSQL standard format: `postgres://<user>:<password>@<host>:<port>/<db>`. For example: `postgres://openmaic:openmaic-dev@localhost:5432/openmaic`. This is documented in `packages/docs/content/docs/deployment.mdx` and parsed by the runtime at `packages/@openmaic/storage/src/runtime/pg.ts`.

### Where is the PostgreSQL persistence provider implemented in the OpenMAIC source code?

The provider is implemented in `packages/@openmaic/storage/src/runtime/pg.ts`. This file creates a `node-postgres` `Pool` instance from `DATABASE_URL` and implements the `PersistenceProvider` interface defined in `packages/@openmaic/storage/src/runtime/types.ts`.

### Does OpenMAIC require code changes to switch from in-memory to PostgreSQL storage?

No. The storage client at `packages/@openmaic/storage/src/lib/storage/client.ts` exports `createPersistence()`, which auto-detects the presence of `DATABASE_URL` and automatically instantiates the PostgreSQL provider instead of the in-memory fallback.

### How do I enable persistence across multiple OpenMAIC server instances?

Run the reference persistence server from `packages/@openmaic/storage/src/server/index.ts`. This process exposes the storage interface via JSON-RPC, allowing multiple OpenMAIC nodes to share the same PostgreSQL backend by communicating with the reference server rather than connecting to the database directly.