Skip to main content

Storage backends

Where turns live: in the process, a SQLite file, Postgres, MongoDB or your own store.

5 min readUpdated November 2026

Choose a store

Pass a store, a SQLite path or a database URL as the first argument of Memory, or as --db (or LLMSLIM_MEMORY_DB) to llmslim serve, llmslim mcp and llmslim import.

StoreUse
InMemoryStore()Tests and short-lived agents; the default for Memory().
SQLiteStore(path)One file, Python's built-in sqlite3, safe across threads. Memory("memory.db") uses it.
PostgresStore(url)Postgres 12+ (self-hosted, Supabase, Neon, RDS) through psycopg 3, for several processes or machines. Memory("postgresql://...") uses it. pip install "llmslim[postgres]".
MongoStore(url)MongoDB 6.0+ (standalone, replica set or Atlas) through PyMongo, for several processes or machines. Memory("mongodb://...") and Memory("mongodb+srv://...") use it. pip install "llmslim[mongodb]".

SQLite

The default for the command-line tools is ~/.llmslim/memory.db, shared by llmslim mcp and llmslim serve. Back the file up if the memory matters.

sqlite.pypython
from llmslim.memory import Memory

memory = Memory("memory.db")

Postgres

Pass a URL and the store opens a small connection pool; you can pass your own psycopg_pool.ConnectionPool, or an autocommit psycopg.Connection, instead. It creates its table (llmslim_memory, or table=...) and a <table>_meta version table if they don't exist, under an advisory lock, so several processes can start at once. Times are stored as TIMESTAMPTZ and come back in UTC.

postgres.pypython
# pip install "llmslim[postgres]"
from llmslim.memory import Memory

memory = Memory("postgresql://llmslim:<password>@db.example.com:5432/llmslim")
memory.add({"role": "user", "content": "I moved to Pune last month."}, user_id="asha")
print(memory.search("Where did I move to?", user_id="asha").text)
terminalbash
pip install "llmslim[server,postgres]"
LLMSLIM_MEMORY_DB="postgresql://llmslim:<password>@db.example.com:5432/llmslim" llmslim serve --host 0.0.0.0

Pass the URL in the environment rather than as --db, so the password stays out of the process list.

MongoDB

pip install "llmslim[mongodb]" brings PyMongo 4.13 or newer, and dnspython, which mongodb+srv:// URLs need. Pass a URL and the store opens and closes its own client, or pass your own MongoClient or Database. The database is database=..., else the one in the URL's path, else llmslim; admin, local and config are refused. One collection holds the turns (llmslim_memory, or collection=...); its indexes are created when the store opens.

  • Atlas: add the public IP of every machine that runs llmslim to the project's IP access list, and give the database user the readWrite role on the memory's database, nothing more. Escape special characters in the password (@ is %40).
  • Writes: on a replica set or a sharded cluster (Atlas is always one), each add is one transaction, stored whole or not at all. A standalone server has no transactions; there a batch that hits a duplicate id is undone. llmslim import writes at most 500 turns or about 4 MB at a time, inside MongoDB's 60-second transaction limit.
  • Caller values are data: ids and scope values must be strings and are matched with $eq, and metadata keys MongoDB would read as operators or paths are stored as JSON text and come back as given.
  • Timeouts: PyMongo waits up to 30 seconds for a server; add serverSelectionTimeoutMS=5000 to the URL to fail sooner.
mongodb.pypython
from llmslim.memory import Memory, MongoStore

memory = Memory("mongodb://llmslim:<password>@db.example.com:27017/llmslim?authSource=admin")
memory = Memory(MongoStore("mongodb://localhost:27017", database="myapp", collection="agent_memory"))
Atlasbash
export LLMSLIM_MEMORY_DB="mongodb+srv://llmslim:<password>@cluster0.example.mongodb.net/llmslim?retryWrites=true&w=majority"
llmslim serve --host 0.0.0.0

When the database is down

When Postgres or MongoDB can't be reached, llmslim serve answers a 503 with "type": "store_unavailable" and Retry-After: 5, and the llmslim mcp tools fail with "the memory store can't be reached right now; try again shortly". Neither shows a host, URL or driver message, and both work again when the database is back, without a restart. If the store can't be opened at start (an unreachable database, a wrong password, a missing extra), the server exits with one line saying why, without the password.

Your own store

A store only persists and lists turns. Any object with the MemoryStore methods works, so another database can plug in without changing selection:

  • add(items), list(scope, since=None, until=None) (oldest first), get(item_id);
  • update(item_id, content=None, metadata=None), delete(item_id), delete_scope(scope).

The signatures are in the API reference.

Stored memory across releases

From 1.0, a SQLite file, Postgres table or MongoDB collection written by a 1.x release opens in every later 1.x release. A release that changes the schema upgrades the store when it opens it, and says so in the CHANGELOG. An older release refuses a store with a newer schema rather than misreading it.

Questions

Does the store change what search returns?

No. A store only persists and lists turns; selection is the same on every store.

Can several processes share one memory?

A few processes on one host can share a SQLite file. For more, or for servers on several hosts, use Postgres.