How to Set Up PostgreSQL Persistence for OpenMAIC: A Complete Docker Guide
To set up PostgreSQL persistence for OpenMAIC, copy .env.example to .env.local, configure the DATABASE_URL connection string pointing to the Docker PostgreSQL service, set the required build-time environment flags, and launch the server-persistence Docker Compose profile.
By default, OpenMAIC stores classroom state in the browser using IndexedDB. For production stability and multi-user support, you need to enable server-side persistence using PostgreSQL. This guide explains how to configure the server-persistence profile in the THU-MAIC/OpenMAIC repository to persist data across container restarts using PostgreSQL 16.
Prerequisites and Environment Configuration
OpenMAIC requires specific environment variables to connect the Next.js application to the PostgreSQL backend. These settings must be configured before building the Docker images.
Copy the Environment Template
Start by creating your local environment file from the provided template:
cp .env.example .env.local
The .env.example file contains placeholders for all required variables, including database connection details and authentication tokens.
Configure the Database Connection String
Edit .env.local and set DATABASE_URL to point at the PostgreSQL container that Docker Compose will start:
DATABASE_URL=postgres://openmaic:openmaic-dev@postgres:5432/openmaic
This connection string uses the following components:
openmaic– the database user created automatically on first container startopenmaic-dev– the default password (controlled byPERSISTENCE_POSTGRES_PASSWORD)postgres– the Docker service name resolving to the database container5432– the default PostgreSQL portopenmaic– the target database name
Set Persistence Tokens
Add a development token to .env.local for local authentication between the client and server:
PERSISTENCE_DEV_TOKEN=openmaic-local-dev
Important: The value must match the NEXT_PUBLIC_PERSISTENCE_TOKEN you set during the Docker build step.
Launching the Server Persistence Profile
Unlike runtime variables, NEXT_PUBLIC_PERSISTENCE and NEXT_PUBLIC_PERSISTENCE_TOKEN are build-time flags. You must export them before Docker builds the image to ensure the client bundle includes the correct API endpoints.
Run the following command to build and launch the stack:
NEXT_PUBLIC_PERSISTENCE=1 \
NEXT_PUBLIC_PERSISTENCE_TOKEN=openmaic-local-dev \
docker compose --profile server-persistence up --build
This command starts three key components defined in docker-compose.yml:
openmaic– The Next.js application running on Node 22postgres– PostgreSQL 16 with the node-postgres driveropenmaic-postgres– A named Docker volume that persists database files across container restarts
The openmaic-postgres volume retains all data. Note that PERSISTENCE_POSTGRES_PASSWORD only initializes the superuser password on the first volume creation; changing this variable later will not update existing credentials.
Verifying Database Persistence
Once the containers are running, confirm that data persists outside the browser.
Test Via the Application
- Navigate to
http://localhost:3000(default port). - Create a classroom or upload a course document.
- Refresh the browser page or run
docker compose restart. - Verify the data remains loaded, confirming it is stored in PostgreSQL rather than IndexedDB.
Inspect Data Directly
Connect to the running PostgreSQL container using the psql client to inspect tables directly:
docker exec -it $(docker ps -q -f name=postgres) psql -U openmaic -d openmaic
You can query the runtime state tables to verify that classroom data is committed to disk.
Key Implementation Files
Understanding the source files helps debug connection issues or extend persistence functionality.
.env.example
This template in the repository root defines all required environment variables, including DATABASE_URL and PERSISTENCE_DEV_TOKEN, ensuring consistent configuration across development environments.
docker-compose.yml
The Compose configuration defines the server-persistence profile, service dependencies between the OpenMAIC app and PostgreSQL, and the named volume openmaic-postgres for data durability.
packages/@openmaic/storage/runtime-store.pg.ts
This TypeScript file implements the PostgreSQL-backed persistence layer used by the server-side API. It handles connection pooling, query execution, and serialization of classroom state to relational tables.
app/workspace/page.tsx
The frontend entry point checks NEXT_PUBLIC_PERSISTENCE at build time to determine whether to instantiate the IndexedDB client-side store or proxy requests through the server persistence API.
packages/docs/content/docs/deployment.mdx
The official documentation file contains human-readable deployment instructions and advanced configuration options for production PostgreSQL setups.
Summary
- Copy
.env.exampleto.env.localand setDATABASE_URLtopostgres://openmaic:openmaic-dev@postgres:5432/openmaic. - Export
NEXT_PUBLIC_PERSISTENCE=1and matchingNEXT_PUBLIC_PERSISTENCE_TOKENas build-time flags before running Docker commands. - Launch the stack using
docker compose --profile server-persistence up --buildto start both the Node.js application and PostgreSQL 16. - Persist all classroom state and course data in the named Docker volume
openmaic-postgres, ensuring survival across container restarts.
Frequently Asked Questions
Why does changing the PostgreSQL password environment variable not affect my existing data?
The PERSISTENCE_POSTGRES_PASSWORD variable only initializes the database superuser password when the openmaic-postgres volume is created for the first time. Because the volume persists across container restarts, subsequent changes to this environment variable do not alter the existing PostgreSQL user credentials or database files.
Can I connect OpenMAIC to an external PostgreSQL database instead of the Docker container?
Yes. Update the DATABASE_URL in .env.local to point to your external instance (e.g., postgres://user:pass@db.example.com:5432/openmaic). Ensure the database is network-accessible from the OpenMAIC container and that the schema is compatible with the queries implemented in packages/@openmaic/storage/runtime-store.pg.ts.
What is the difference between client-side and server-side persistence in OpenMAIC?
Client-side persistence stores classroom state in the browser's IndexedDB, as implemented in app/workspace/page.tsx. Server-side persistence activates when NEXT_PUBLIC_PERSISTENCE=1 is set at build time, causing the application to route all storage operations through HTTP API calls to the PostgreSQL backend defined in the DATABASE_URL.
Is it safe to use the development token in production environments?
No. The PERSISTENCE_DEV_TOKEN and NEXT_PUBLIC_PERSISTENCE_TOKEN are intended strictly for local development. Never use these default values in public deployments. For production, implement a proper authentication layer and avoid exposing NEXT_PUBLIC_PERSISTENCE unless your backend API includes robust authorization checks.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →