Persistent memory of the AI agents: the official Mem0 REST server extracts facts from conversations with the LLM, stores them with their embedding in PostgreSQL (pgvector) per user, agent or run, and answers semantic searches, updates, history and deletions. LLM and embedding calls go through the LiteLLM gateway of the platform (OpenAI compatible); every call is authenticated (admin API key, user API keys or JWT) and no telemetry leaves the host.
Generated from catalog/services/mem0.yaml: do not edit by hand.
Summary
| |
|---|
| Version | 2.2.1 |
| Use | install and configure, configure and connect |
| Layer | functional (AI catalog) |
| Category | AI memory |
| Subcategory | Persistent agent memory |
| Installation methods | python |
| External connection | no |
| Sandbox only | no |
Licence
| |
|---|
| SPDX identifier | Apache-2.0 |
| Licence policy | core licence (MIT or Apache-2.0) |
| Licence exception | - |
| Licence note | The server sources (server/ of the v2.2.1 archive, sha256 2d203947596fbbfeaf06e5311c087a6b837566528016013aff15ad2a8a4103c5) and its LICENSE are rendered from templates/mem0/server, identical to the archive except two text only edits that change no behaviour (one log message of main.py and the dashes of docstrings and a comment of telemetry.py: the catalog refuses Jinja markers and dashes in rendered files); the Python dependencies are under OSI licences (MIT, BSD, Apache-2.0, ISC, MPL-2.0, LGPL-3.0-only for psycopg, Unlicense, PSF-2.0). The web dashboard of the release (Next.js) is not delivered: no versioned official image exists and the python method cannot build it. No podman method either: the Docker Hub image mem0/mem0-api-server has no versioned tag (one floating tag of 2025-09-10, before v2) and the official documentation names no other image. The graph memory (Neo4j) and spaCy are not installed: the entity linking and the lemmatized keyword scoring stay off. |
| Platform component | mem0 |
Packages and artifacts
A package the project of the service publishes (its image, its binary archive, its Python or OS package) carries the licence of the service; a third-party package carries the licence written on its row, read from the official upstream metadata.
| Kind | Package | Version | Licence | Details |
|---|
| Python package | mem0ai | 2.2.1 | Apache-2.0 | interpreters, in order of preference python3.12 |
| Python package | fastapi | 0.115.8 | MIT | interpreters, in order of preference python3.12 |
| Python package | uvicorn | 0.34.0 | BSD-3-Clause | interpreters, in order of preference python3.12 |
| Python package | pydantic[email] | 2.10.4 | MIT | interpreters, in order of preference python3.12 |
| Python package | python-dotenv | 1.2.2 | Apache-2.0 | interpreters, in order of preference python3.12 |
| Python package | psycopg[binary] | 3.3.7 | Apache-2.0 | interpreters, in order of preference python3.12 |
| Python package | psycopg-pool | 3.3.3 | Apache-2.0 | interpreters, in order of preference python3.12 |
| Python package | sqlalchemy | 2.1.6 | Apache-2.0 | interpreters, in order of preference python3.12 |
| Python package | alembic | 1.20.1 | Apache-2.0 | interpreters, in order of preference python3.12 |
| Python package | passlib[bcrypt] | 1.7.4 | Apache-2.0 | interpreters, in order of preference python3.12 |
| Python package | bcrypt | 4.0.1 | Apache-2.0 | interpreters, in order of preference python3.12 |
| Python package | python-jose[cryptography] | 3.5.0 | Apache-2.0 | interpreters, in order of preference python3.12 |
| Python package | cryptography | 50.0.2 | Apache-2.0 OR BSD-3-Clause | interpreters, in order of preference python3.12 |
| Python package | posthog | 7.82.2 | Apache-2.0 | interpreters, in order of preference python3.12 |
| Python package | slowapi | 0.1.10 | Apache-2.0 | interpreters, in order of preference python3.12 |
| Python package | openai | 3.42.1 | Apache-2.0 | interpreters, in order of preference python3.12 |
| Python package | pixeltable-pgserver | 0.7.1 | Apache-2.0 | interpreters, in order of preference python3.12 |
Supported systems and architectures
| Method | Operating systems | Architectures |
|---|
python | RHEL family (dnf), Debian family (apt), Arch Linux (pacman) | x86_64, aarch64 (not restricted by the descriptor) |
Certified host systems: RHEL 8/9/10, Rocky Linux 8/9/10, AlmaLinux 8/9/10, Oracle Linux 8/9, CentOS Stream 9/10, Ubuntu 22.04/24.04, Debian 12, Arch Linux (rolling). The host preflight accepts these systems (other releases of a known family give a warning, end of life releases are refused) and the x86_64 and aarch64 architectures.
Prerequisites
Host
- at least 1024 MB of memory (blocking,
memory).
- at least 1 CPU (blocking,
cpu).
- at least 2048 MB free for
/var/lib/navin (blocking, disk).
Network and ports
| Component | Port name | Port | Opened in the host firewall |
|---|
mem0-server | api | 8720/tcp | yes |
mem0-server | api_local | 8720/tcp | no |
Services and connections needed
Details and resolution: see Dependencies.
Installation methods and modes
| Method | Default | What the method uses |
|---|
python | yes | a Python virtual environment holding the Python packages of the descriptor |
Components
| Component | Kind | Installation methods | Ports |
|---|
Mem0 REST server (mem0-server) | master | python | 8720/tcp, 8720/tcp |
Request log pruner (request-log-pruner) | worker | python | - |
request-log-pruner runs only on a host that also runs mem0-server.
Single server (single) (default)
One Mem0 server and its request log pruner.
What the mode deploys:
| Component | Placement |
|---|
mem0-server | min 1, max 1 |
request-log-pruner | min 1, max 1 |
Install this service
The install wizard of the Navin Manager plans, validates and runs the installation; you need the services:install permission on the cluster.
-
Open the wizard. In Clusters, choose the row action Install services of the target cluster. The wizard opens on its first step, Service.
-
Choose the service. On the Service step, select Mem0. The card shows the licence Apache-2.0 and the dependencies the installation needs.
-
Choose the hosts and the mode. On the Hosts step, tick the hosts, then choose the Mode: single (default). Each mode deploys the components listed in Installation methods and modes. With several components, place each one on its hosts in Component placement (Suggest placement proposes a placement that respects the cardinalities).
-
Bind the dependencies. On the Bindings step, choose for each dependency (database, app, llm) Install with the platform or Use an existing connection; an optional dependency can stay on No binding.
-
Configure. On the Configure step, review the parameters (see Configuration parameters). Passwords left empty with a generated default are generated and sealed by the Manager.
-
Review and install. On the Install step the Manager validates the plan and shows the installation order; when it says "The plan is valid. Ready to install.", choose Install. A highly available mode is installed only when its HA checks pass.
-
Verify. The operation ends when the health checks of every instance pass (see Health checks); the service then shows as running in Services. Open the service and choose Run the smoke test in the Checks card: In a space of its own (user_id navin-smoke-<nonce>): checks that a call without key is refused, stores a memory (embedding call), asks the LLM through the server, finds the memory by semantic search, updates it, reads it back, deletes it, checks the space is empty, then deletes the space whatever happened.
Connect an existing service
| |
|---|
| Schemes | https, http |
| Default port | 8000 |
| Authentication | required |
| Health check | /openapi.json |
| Authentication method | Fields | Description |
|---|
api_key | api_key | ADMIN_API_KEY of the server or a user API key (m0sk_...), sent as X-API-Key. |
Official documentation: https://docs.mem0.ai/open-source/features/rest-api
High availability
Topology per mode
| Modes | Highest catalog level | Distribution | Quorum component | Fault domains | Description |
|---|
single | standalone (standalone) | single (single) | - | 1 | One server: its loss stops the memory API until it is restarted or restored; the memories stay in PostgreSQL. |
Notes
- No replicated mode: the history of the memories and the recent messages used as extraction context live in a local SQLite file (HISTORY_DB_PATH, mem0/memory/storage.py), the rate limits of the authentication routes are counted in memory per process (slowapi) and the migrations run at each start. Two servers behind a load balancer would each keep a partial history.
- The memories, their vectors, the users and the keys are in PostgreSQL: with the highly available PostgreSQL service a lost host is replaced by a reinstall and the restore of the history file.
- The server exposes no metrics endpoint: the observability uses blackbox probes of /openapi.json and /auth/setup-status.
Configuration parameters
Network
| Parameter | Type | Default | Allowed values | Required | Secret | Restart | Description |
|---|
API port (port) | port | 8720 | - | no | no | yes | Port of the REST API (8000 upstream, moved off the port of vLLM and Opik). |
API exposure (listen_scope) | enum | network | network, local | no | no | yes | network: the API listens on the private address of the host only (never on every address) and the host firewall opens it to the consumers; local: loopback only, for consumers on the same host. It is never published by a gateway. |
TLS (tls_enabled) | bool | false | - | no | no | yes | Serve the API over TLS (uvicorn --ssl-certfile and --ssl-keyfile) with the certificate the Manager issues to the host; the binding of the consumers then uses https. |
Concurrent requests (limit_concurrency) | int | 64 | min 4, max 1024 | no | no | yes | Requests served at once (uvicorn --limit-concurrency); beyond, the server answers 503. |
Models
| Parameter | Type | Default | Allowed values | Required | Secret | Restart | Description |
|---|
LLM (llm_model) | string | qwen-local | ^[A-Za-z0-9._:/@-]{1,128}$ | no | no | yes | Model name of the gateway used for the fact extraction (JSON mode); default qwen-local, the default served model name of a vLLM engine bound to LiteLLM (the gateway has no default entry, audit P5B-010). |
LLM temperature (llm_temperature) | float | 0.2 | min 0, max 2 | no | no | yes | Temperature of the extraction calls (0.2 upstream). |
Embedding model (embedder_model) | string | bge-m3 | ^[A-Za-z0-9._:/@-]{1,128}$ | no | no | yes | Embedding model name of the gateway; default bge-m3, served by a vLLM engine in embedding mode bound to LiteLLM. |
Vector size (embedding_dims) | int | 1024 | min 64, max 16000 | no | no | yes | Size of the vectors the embedding model returns (1024 for bge-m3): the vector column of the collection is created with it. Changing it on a collection that holds memories needs a new collection name. |
Send the vector size (embedding_send_dimensions) | bool | false | - | no | no | yes | Send the dimensions parameter in the embedding calls (models with Matryoshka embeddings only: vLLM refuses it for the other models). (advanced) |
Gateway key (llm_api_key) | password | (empty) | - | no | yes | no | LiteLLM virtual key of Mem0 (sk-...); empty, the master key of the bound gateway is used. |
Storage and retention
| Parameter | Type | Default | Allowed values | Required | Secret | Restart | Description |
|---|
Collection (collection_name) | string | memories | ^[a-z_][a-z0-9_]{0,62}$ | no | no | yes | Table of the memories in the memory database (POSTGRES_COLLECTION_ NAME); the entities use the table of the same name with the suffix _entities. |
Request log retention (request_log_retention_days) | int | 30 | min 1, max 3650, days | no | no | yes | Rows of the request log older than this are deleted by the request-log-pruner component (official prune_request_logs.py). |
Pruning interval (prune_interval_hours) | int | 24 | min 1, max 168, hours | no | no | yes | Hours between two runs of the request log pruning. |
Security
| Parameter | Type | Default | Allowed values | Required | Secret | Restart | Description |
|---|
Admin API key (admin_api_key) | password | generated | - | no | yes | no | ADMIN_API_KEY of the server (X-API-Key header, role admin), given to the consumers as the api_key secret of the api endpoint; rotated by a new value and a restart. |
JWT secret (jwt_secret) | password | generated | - | no | yes | no | JWT_SECRET signing the access and refresh tokens of the users; changing it ends every session. |
Administrator e-mail (admin_email) | string | mem0-admin@navin.internal | ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$ | no | no | no | Login of the first administrator, created by the launcher before the API listens (the public registration route is then closed). |
Administrator password (admin_password) | password | generated | - | no | yes | no | Initial password of the first administrator (bcrypt hash in the app database); once the account exists it is changed in the server only (POST /auth/change-password). |
Observability
| Parameter | Type | Default | Allowed values | Required | Secret | Restart | Description |
|---|
Log level (log_level) | enum | info | critical, error, warning, info, debug | no | no | no | Verbosity of uvicorn. |
Dependencies
For each active dependency the Manager takes the first of: the binding chosen in the wizard; a service of the same installation that provides it; a service already installed in the cluster; the only connection of the expected type. Otherwise an optional dependency stays unbound, and a required one is added to the installation in its default mode (the column below names the catalog service added).
| Binding | Provided by | Connection type | Endpoint | Optional | When nothing is bound | Description |
|---|
database | postgresql (versions >= 13) | postgresql | sql | no | postgresql is added to the installation | Memory database (database mem0): the pgvector collection of the memories and of the entities. The provisioning creates the role mem0, owner of its databases only, and the vector extension. |
app | postgresql (versions >= 13) | postgresql | sql | no | postgresql is added to the installation | App database (database mem0_app) of the server: users, API keys, refresh tokens, settings and request log (Alembic migrations). It must be on the same PostgreSQL server as the memory database. |
llm | litellm | - | api | no | litellm is added to the installation | OpenAI compatible gateway of the LLM (fact extraction) and of the embedding model; the vLLM and Ollama engines of the Manager are reached through it. |
Checks of the bound endpoints
- the endpoint
/v1/models of the binding llm answers with the status 200 and lists the values of llm_model, embedder_model, checked by the Manager before the installation (blocking, llm_models).
Endpoints
| Endpoint | Scheme | Component | Port | Path | TLS parameter | Binding parameters | Binding secrets | Provisioning command |
|---|
api | http | mem0-server | 8720 (port) | - | tls_enabled | collection, embedding_dims | api_key | - |
Client configuration files
Files rendered for the client configuration download:
Commands
| Command | Component | Target | Description |
|---|
Effective configuration (configuration) | mem0-server | first host | Configuration the server runs with (GET /configure, secrets redacted by the server). |
Prune the request log (prune_request_logs) | request-log-pruner | first host | Deletes now the request log rows older than the retention. |
Apply the migrations (migrate) | mem0-server | first host | Applies the Alembic migrations of the release to the app database (also done at every start of the server). |
Recent logs (logs) | mem0-server | chosen host | Last lines of the server journal. |
Health checks
Liveness (per instance)
| Component | Check | Details |
|---|
mem0-server | HTTP {{ 'https' if config.tls_enabled else 'http' }}://{{ host.fqdn if config.tls_enabled and config.listen_scope == 'network' else ((host.ip or '127.0.0.1') if config.listen_scope == 'network' else '127.0.0.1') }}:{{ config.port }}/openapi.json | Expected 200; Expected Mem0 REST APIs; 60 retries; interval 2 s; timeout 5 s |
request-log-pruner | {{ paths.opt }}/venv/bin/python {{ paths.opt }}/server/navin_prune.py --check {{ paths.data }}/home/prune.status {{ config.prune_interval_hours * 7200 + 600 }} | 20 retries; interval 3 s; timeout 30 s |
Readiness (service check)
| Check | Details |
|---|
HTTP {{ 'https' if config.tls_enabled else 'http' }}://{{ host.fqdn if config.tls_enabled and config.listen_scope == 'network' else ((host.ip or '127.0.0.1') if config.listen_scope == 'network' else '127.0.0.1') }}:{{ config.port }}/auth/setup-status | Expected 200; Expected "needsSetup":false; 10 retries; interval 3 s; timeout 10 s |
Smoke test
In a space of its own (user_id navin-smoke-<nonce>): checks that a call without key is refused, stores a memory (embedding call), asks the LLM through the server, finds the memory by semantic search, updates it, reads it back, deletes it, checks the space is empty, then deletes the space whatever happened. (mem0-server: refused_without_key, create, llm, search, update, read_back, delete, gone, cleanup)
Preflight checks
| Check | Type | Meaning | Severity | Components |
|---|
memory | memory_mb {"min": 1024} | at least 1024 MB of memory | blocking | mem0-server |
cpu | cpu_count {"min": 1} | at least 1 CPU | blocking | mem0-server |
disk | disk_free_mb {"min": 2048} | at least 2048 MB free for /var/lib/navin | blocking | mem0-server |
api_port_free | port_free {"param": "port"} | port 8720 free on the host | blocking | mem0-server |
llm_models | http_reachable {"binding": "llm", "path": "/v1/models", "bearer_secret": "token", "contains_params": ["llm_model", "embedder_model"], "timeout_s": 10} | the endpoint /v1/models of the binding llm answers with the status 200 and lists the values of llm_model, embedder_model, checked by the Manager before the installation | blocking | mem0-server |
Backup and restore
pg_dump (custom format, without owner nor privilege) of the memory and app databases and an online SQLite backup of the history file; verify reads the table of contents of each dump and checks the integrity of a copy of the history. Restore: the server is stopped, pg_restore --clean --if-exists replaces the objects of each database in one transaction (the vector extension stays the one of the provisioning) and the history file is replaced.
| |
|---|
| Format | mem0-pgdump |
| Component | mem0-server |
| Files | {{ backup.dir }}/memories.dump, {{ backup.dir }}/app.dump, {{ backup.dir }}/history.db |
| Restore test | yes |
| Instances stopped for the restore | yes |
Upgrade
| |
|---|
| Supported from | |
| Stateful | yes |
| Backup before the upgrade | yes |
| Rollback | no (The Alembic migrations of the server only go forward (they run at every start of a new release and the Manager never downgrades them): the way back is the restore of the backup taken before the upgrade.) |
| Migrations | alembic_head |
Uninstall
Paths removed when the data is purged: {{ paths.data }}, {{ paths.log }}.
Quick links
- API reference:
{{ 'https' if config.tls_enabled else 'http' }}://{{ host.fqdn }}:{{ config.port }}/docs
Upstream documentation