> Full SurrealDB documentation index: https://surrealdb.com/docs/llms.txt

# Migrate from Mem0

Mapping concepts and incremental migration.

This guide maps Mem0 concepts to their SurrealDB Agent Memory equivalents, then describes an incremental migration that can run both systems in parallel.

## Concept mapping

| Mem0 concept | SurrealDB Agent Memory equivalent | Notes |
|---|---|---|
| User ID | Scope dimension `user` | SurrealDB Agent Memory scopes are multi-dimensional; `user` is one axis |
| Agent ID | Scope dimension `agent` | Combine with `user` for agent-per-user isolation |
| Run ID | Session | SurrealDB Agent Memory sessions are first-class records with richer metadata |
| Memory (flat string) | Entities + attributes + relations | SurrealDB Agent Memory extracts structured triples from text |
| `add()` | `remember()` | SurrealDB Agent Memory also deduplicates and reconciles on write |
| `search()` | `recall()` | SurrealDB Agent Memory adds graph-density reranking |
| `get_all()` | `profile()` | Returns structured snapshot, not a flat list |
| `delete()` | `forget()` | Query-driven; `POST /scopes/forget` erases a whole subtree |
| History | Session turns + temporal attributes | SurrealDB Agent Memory tracks `valid_from`/`valid_until` on attributes |

## SDK migration

### Python

**Mem0:**
```python
from mem0 import Memory

m = Memory()
m.add("I prefer vegetarian food.", user_id="alice")
results = m.search("What are Alice's food preferences?", user_id="alice")
```

**SurrealDB Agent Memory:**
```python
from surrealdb.memory import AsyncMemory

client = AsyncMemory(
    context="<your-context-id>",
    endpoint="https://<your-context-host>",
    api_key="sp-...",
)

await client.remember("I prefer vegetarian food.", scopes=["user/alice"])
results = await client.recall("What are Alice's food preferences?", k=5, lens=["user/alice"])
for hit in results.hits:
    print(hit.text)
```

### JavaScript

**Mem0:**
```javascript
import { Memory } from "mem0ai";

const m = new Memory();
await m.add("I prefer vegetarian food.", { user_id: "alice" });
const results = await m.search("food preferences", { user_id: "alice" });
```

**SurrealDB Agent Memory:**
```javascript
import { AgentMemory } from "@surrealdb/memory";

const client = new AgentMemory({
  endpoint: process.env.AGENT_MEMORY_ENDPOINT!,
  context: "dev",
  apiKey: process.env.AGENT_MEMORY_API_KEY!,
});

await client.remember("I prefer vegetarian food.", { scopes: ["user/alice"] });
const results = await client.recall("What are Alice's food preferences?", { k: 5, lens: ["user/alice"] });
console.log(results.hits);
```

## Key differences

**Structured extraction**: Mem0 stores memories as flat text strings. SurrealDB Agent Memory extracts structured entities, attributes, and relations. When you write "Alice prefers vegetarian food", it creates an entity `person/alice` with attribute `food_preference = "vegetarian"`. Future writes that contradict this (e.g. "Alice now eats fish") update the attribute with a supersession chain, so you can see the history.

**Conflict resolution**: Mem0 stores new memories alongside old ones. SurrealDB Agent Memory detects when a new memory contradicts a stored attribute and automatically supersedes the old value. The old value is not deleted - it is marked as superseded with a timestamp.

**Scoped multi-tenancy**: Mem0 uses separate `user_id` and `agent_id` parameters. SurrealDB Agent Memory uses **slash-path scope** (for example `["org/acme/user/alice"]`). A reader sees records at the scopes its grants cover and below them, never records tagged at an ancestor scope, so a key granted `org/acme/*` can read every user's memory under `org/acme`.

**Documents versus conversation**: Mem0 treats all memory uniformly. SurrealDB Agent Memory records the kind of source behind every fact, such as an uploaded `document` or a conversation `turn`, and sorts facts into three memory categories: identity, knowledge and context. When a conversation contradicts a fact from a document, neither value replaces the other: both are kept and an `uncertainty` is raised for someone to resolve. See [Authority when pillars meet](/docs/agent-memory/reasoning/authority-hierarchy.md).

## Incremental migration strategy

### Step 1: run both systems in parallel

Wrap your memory calls in a thin adapter that writes to both Mem0 and SurrealDB Agent Memory:

```python
class MemoryAdapter:
    def __init__(self, mem0_client, agent_memory_client):
        self.mem0 = mem0_client
        self.agent_memory = agent_memory_client
    
    async def add(self, content: str, user_id: str):
        # Write to both
        self.mem0.add(content, user_id=user_id)
        await self.agent_memory.remember(content, scopes=[f"user/{user_id}"])
    
    async def search(self, query: str, user_id: str, use_agent_memory: bool = False):
        if use_agent_memory:
            return await self.agent_memory.recall(query, k=5, lens=[f"user/{user_id}"])
        return self.mem0.search(query, user_id=user_id)
```

### Step 2: validate recall quality

Compare recall results between the two systems for a sample of production queries. Use the `use_agent_memory=True` flag on a percentage of traffic while monitoring for quality regressions.

### Step 3: migrate existing memories

Export existing Mem0 memories and replay them into SurrealDB Agent Memory:

```python
existing_memories = m.get_all(user_id="alice")

session = await client.sessions.create(scopes=["user/alice"])
for item in existing_memories:
    await client.remember(item["memory"], session_id=session.id)
```

SurrealDB Agent Memory's reconciliation pipeline deduplicates on write, so replaying memories that contain the same facts will produce correct structured state rather than duplicates.

### Step 4: cut over

Once recall quality is satisfactory, remove the dual-write and switch reads to SurrealDB Agent Memory only.

## Session management difference

Mem0's `add()` takes a `user_id` directly - there is no concept of a session. Every SurrealDB Agent Memory turn belongs to a session, but you do not have to create one: a write without a `session_id` creates a session for itself and returns its id. The nearest equivalent to Mem0's `add()` is:

```python
# One-shot add; the write creates its own session
result = await client.remember(content, scopes=[f"user/{user_id}"], role="user")
print(result.session_id)
```

Sessions have no close step. If your application has natural conversation boundaries, create a session per conversation and pass its id to each write, so the turns are grouped together.
