Migrating from Mem0 to MemorySync, step by step (with a dry run first)
Disclosure: I'm Mohammed, founder of MemorySync, so read this as a vendor's page. I drafted it with AI assistance and checked every claim against each company's own docs as of Oct 25, 2026.
Code status: on Oct 25, 2026 I ran the CLI dry runs in steps 2 and 3 and a real import (step 4) with memorysync-cli 1.6.1 on small test exports against the live MemorySync API, plus the MemorySync calls in step 5 (add, query, PATCH, forget). The Mem0 calls are quoted from Mem0's docs and were not run.
This is the "how", not the "whether". If you're still deciding, start with Mem0 alternative: how to compare hosted agent memory. If you've decided to move, here's the order that keeps it reversible.
Before you start: the one thing that changes
In Mem0 you pass the user on each call: user_id on add, and filters={"user_id": ...} on search (Mem0 quickstart). In MemorySync the user is a request header, X-End-User-ID, set once on the client as end_user_id (Authentication).
MemorySync's guide warns that a missing X-End-User-ID "does not raise - it writes into the wrong scope" (Migrating from Mem0). Set the header on every call. Every step below is built around getting that mapping right.
Step 1: Export from Mem0
Use the Mem0 dashboard export or the export API. Per MemorySync's guide, the export holds records with id, content, metadata and created_at. Make sure user_id is included on every record (see step 3).
Step 2: Dry-run the import
# Reports what would be written, per user. Writes nothing.
npx memorysync-cli migrate mem0 --file mem0_export.json --dry-run
When I ran this on a sample export where every record had a user_id, it printed the record count, the number of end users, the number of requests (at 50 records per request), and a "Would write" count per user. It wrote nothing.
Step 3: Fix records with no user
When I ran it on an export with one record missing user_id, the dry run stopped with exit code 2, named the record, said "Nothing was written", and suggested a re-export that includes user_id. That's documented behaviour: the CLI refuses any record whose user can't be determined, rather than guessing.
Re-export from Mem0 with user_id on every record, then run the dry run again.
Step 4: Run the import
Once the dry run looks right, drop --dry-run and follow the migration guide. Per the guide, the CLI:
- groups records by Mem0
user_idand writes each group under that end-user scope; - sends each Mem0
idasclient_ref, so re-running reports records that already landed instead of storing them again; - maps categories to tags and keeps
id,created_at,agent_id,app_idandrun_idin metadata; - batches 50 records per request.
The original timestamp is kept as metadata.mem0_created_at. MemorySync assigns its own created_at, so sort on the metadata field if original order matters.
Step 5: Change your calls
These rows appear in both vendors' current docs:
| Mem0 (Mem0 docs) | MemorySync (MemorySync docs) |
|---|---|
client.add(messages, user_id="alice") |
POST /memory/add with text; SDK client.add("...") on a client created with end_user_id="alice" |
client.search(query, filters={"user_id": "alice"}, top_k=5) |
POST /memory/query with query and k (1 to 50, default 5); scope from the header |
client.update(memory_id, ...) (PUT /v1/memories/{memory_id}/) |
PATCH /memory/{memory_id} with tags, importance, metadata, source or event_type |
client.delete(memory_id) (DELETE /v1/memories/{memory_id}/) |
DELETE /memory/forget with a memory_ids list |
Two differences to plan for. Mem0's update edits content, metadata, timestamp or expiration date. MemorySync's PATCH doesn't list the memory text as an editable field. And MemorySync memory ids are integers, so keep the Mem0 id in metadata (the CLI does this) rather than reusing it as an id.
# From docs.memorysync.io (run against the live API on Oct 25, 2026)
import os
from memorysync import MemorySyncClient
client = MemorySyncClient(
api_key=os.environ["MEMORYSYNC_API_KEY"],
base_url="https://api.memorysync.io",
project_id=os.environ.get("MEMORYSYNC_PROJECT_ID") or None,
end_user_id="alice",
)
client.add("User prefers dark mode")
hits = client.query("user preferences", k=5)
Step 6: Keep both live, then cut over
Run your own real queries against both and compare the results before you cut over. Keep the Mem0 export through a full usage cycle. MemorySync's guide calls it "the cheapest rollback available".
Common questions
Can I re-run the import if it stops halfway?
Per MemorySync's guide, yes. Each Mem0 id is sent as client_ref, and records that already landed are reported as already migrated. In my live test import, the second run printed "Migrated 0 of 2 record(s)" and "2 already migrated on an earlier run". The originals carried mem0_id and mem0_created_at in metadata.
Will Mem0's agent_id and run_id still be there?
Per the guide, they're kept in metadata. They don't become MemorySync scopes. Scope is project plus end user.
Do I have to change every call site?
Yes. User scope moves from call arguments to the client, and top_k becomes k.
Want to see the write-then-recall loop before you migrate anything? The browser playground needs no signup: try MemorySync.
References
- Mem0 Platform quickstart: https://docs.mem0.ai/platform/quickstart
- Mem0 Search Memories API: https://docs.mem0.ai/api-reference/memory/search-memories
- Mem0 Update Memory API: https://docs.mem0.ai/api-reference/memory/update-memory
- Mem0 Delete Memory API: https://docs.mem0.ai/api-reference/memory/delete-memory
- MemorySync, Migrating from Mem0: https://docs.memorysync.io/getting-started/migrate/from-mem0
- MemorySync, Authentication: https://docs.memorysync.io/api/authentication
- MemorySync, Query Memory: https://docs.memorysync.io/api/memory/query
- MemorySync, Update Memory: https://docs.memorysync.io/api/memory/update
- MemorySync, Forget Memory: https://docs.memorysync.io/api/memory/delete
Comments
No comments yet. Start the discussion.