Skip to main content

The tiers

memloom’s storage is an adapter, and the same schema and SQL run on both implementations: The embedded tier is the right default: there is nothing to set up or run, and backup is copying a folder. Reach for the server tier when you want concurrent DB access (the PGLite single-connection lock is the thing you feel), a store bigger than comfortable in one folder, or a store shared across machines.

Backing up the embedded store

The whole store lives in the data folder. Stop the daemon first so the data directory is quiescent:
Restoring is the reverse. config.env travels separately (same folder, one file).

Running against Docker Postgres

1. Start Postgres with pgvector:
2. Point memloom at it. One line in ~/.memloom/config.env:
Then memloom serve. The daemon connects with a pooled pg adapter instead of opening the PGLite folder, and the first init() creates the full schema on an empty database, so there is no separate provisioning step. Everything else (CLI, MCP, viewer, memloom reembed) reads the same config and follows. Two differences from the embedded tier: the data-dir lock is not used (the Postgres server handles concurrency), and the daemon does not start the wire-protocol bridge on 54329 (inspect the server directly with any Postgres client). Embedding memloom as a library instead? The same tier is one constructor argument:
pg is an optional dependency: run pnpm add pg in the project that runs this.

Migrating existing data

Two paths, depending on how much history you care about: Re-ingest (simple, loses history). Point the new store at the same embedding config and replay your sources: context add your files again, re-save what matters. Version chains and resolved conflicts don’t come along. For a store that’s mostly ingested documents, this is usually all you need: documents are mirrors, and re-ingesting reproduces them exactly. Copy the rows (full fidelity). The daemon speaks the Postgres wire protocol on 127.0.0.1:54329, so with the daemon running you can pull data out with standard tools and load it into the Docker database:
Run the target’s schema first (start memloom serve once with MEMLOOM_PG_URL pointed at the Docker database; it creates the schema), then load data-only. The wire server is a single-connection bridge into PGLite. If pg_dump trips over it, fall back to per-table COPY ... TO STDOUT via psql, in dependency order: _memloom_meta, memory_objects, memory_schema, memory_entities, memory_edges, memory_dedup_decisions, context_documents, context_chunks, memory_index_runs, memory_index_events, assistant_sessions, assistant_messages. Skipping the later ones silently drops your schema vocabulary, indexing history, and assistant chats.
The embedding fingerprint travels with the data (it’s a row in _memloom_meta). The engine you run against the migrated store must be configured with the same embedding provider, model, and dims, or init() will refuse to open it (by design). See Configuration.

What stays local no matter what

Whichever tier you run, the trust model doesn’t change: the HTTP API binds to 127.0.0.1, CORS admits only localhost origins, and the only outbound traffic is to the embedding/LLM provider you configured. Self-hosting the database in Docker doesn’t expose memloom to the network unless you publish the ports yourself.