> ## Documentation Index
> Fetch the complete documentation index at: https://docs.maximem.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# How migration works

> The method every Synap migration follows: map your identity model onto scopes, configure the instance for your agent, backfill, pilot, verify, and cut over. Each platform guide builds on this page.

Every migration onto Synap follows the same shape, regardless of where your data comes from. The per-platform guides ([Mem0](/migrations/from-mem0), [Zep](/migrations/from-zep), [Letta](/migrations/from-letta), [Supermemory](/migrations/from-supermemory)) cover how to get data *out* of each source and how its concepts map onto Synap. This page is the method they all share — read it once.

<Note>
  For the SDK methods used below — `batch_create`, idempotency via `document_id`, per-document status — see the [Migration reference](/sdk-reference/migration).
</Note>

## 1. Map your identity model onto scopes

Synap organises memory into three scopes: **client**, **customer**, and **user**. You never name a scope directly — Synap derives it from which identifiers you pass when you ingest:

| `user_id` | `customer_id` | Resulting scope            | Use for                                          |
| --------- | ------------- | -------------------------- | ------------------------------------------------ |
| set       | set           | **user**                   | One person's own history                         |
| not set   | set           | **customer**               | Knowledge shared across everyone at one customer |
| not set   | not set       | **client**                 | Knowledge shared across your entire account      |
| set       | not set       | Rejected on a B2B Instance | —                                                |

The first task in any migration is deciding, for each slice of your source data, which identifiers it should carry. A source that only has a `user_id` concept maps cleanly to user scope; shared or company-wide material belongs at customer or client scope. See [Memory scopes](/concepts/memory-scopes) for the full model.

<Warning>
  Getting this wrong is the highest-impact mistake in a migration. Content placed at client scope is readable across your whole account; content wrongly placed at user scope is invisible to everyone but one person. Step 4 has you verify the assignment before it becomes permanent.
</Warning>

## 2. Configure the Instance for your agent — before you import

Extraction quality depends on your Instance's **Memory Architecture Configuration (MACA)** — a per-instance memory policy generated from the use-case file you supply at instance creation. It governs what gets extracted and how, tuned to your agent's domain and audience. See [Memory Architecture](/concepts/memory-architecture).

Do this **before** the bulk import. If you import against an instance with no use-case file, your historical data is extracted with generic defaults, and you would re-import later to benefit from a tuned configuration. The same MACA governs your migrated history and your live traffic, so configuring first is what makes old data behave as if your agent created it.

## 3. Choose one Instance or many

One Instance per environment (production, staging) is the usual answer. Use a separate Instance per customer only when data residency or the memory architecture genuinely differs between them.

## 4. Decide your `conversation_id` strategy

If your source stores conversations or sessions, map each to a stable `conversation_id` (a UUID per thread). This lets Synap compact long histories and group turns correctly. Sources that store only flat facts don't need this.

## 5. Backfill

Ingest through `batch_create` at `mode="long-range"`:

* Pass `document_created_at` from the source's original timestamp, not today's date — otherwise every memory is dated to import day and time-relative recall answers against the wrong timeline.
* Set `document_id` to the source record's ID. Ingestion is idempotent on it, so a re-run never duplicates.
* Prefer ingesting **original content** (conversations, documents) over a source's pre-extracted memory strings, so Synap extracts natively instead of inheriting the upstream extraction. Each platform guide says which is available.

## 6. Pilot one slice

Before migrating everything, run one representative user or tenant end to end — backfill, then the verification in step 7. Only continue once that slice checks out. A mistake caught on one user is cheap; the same mistake across your whole dataset is not.

## 7. Verify

Two checks, both on the pilot and again after the full run:

* **Scope isolation.** Fetch context as one user with a search term you know belongs to a *different* user, and confirm nothing from that user appears. For client-scoped material, fetch as two users and confirm both can retrieve it.
* **Retrieval coverage.** Fetch for facts you know exist and confirm they come back. Do not compare raw memory counts — Synap and your source extract differently by design, so judge by what you can retrieve.

```python theme={null}
from maximem_synap import MaximemSynapSDK

sdk = MaximemSynapSDK()
await sdk.initialize()

ctx = await sdk.user.context.fetch(
    user_id="user-123",
    customer_id="acme",
    search_query=["dietary preferences"],
)
```

## 8. If you got a scope wrong, fix it one slice at a time

If you discover misplaced data after ingesting, correct only that slice — delete the memories created for it, then re-ingest it at the right scope.

<Warning>
  Do not delete everything and re-run the whole backfill. Ingestion recognises content it has already seen at the same scope for several days and returns the earlier result instead of rebuilding, so a blanket re-run leaves the slices you deleted but did not re-scope permanently gone. Re-ingesting works precisely *because* the scope changed. Keep the IDs of what you ingested until the migration is verified.
</Warning>

## 9. Swap your retrieval call sites

Replace your old retrieval calls with `sdk.user.context.fetch(...)`. Synap returns a `ContextResponse` with typed lists (facts, preferences, episodes, emotions, temporal events) rather than one flat list — iterate over the types your prompt needs. See [Response shapes](/sdk/response-shapes).

## 10. Cut over

Add [graceful degradation](/patterns/graceful-degradation) so memory never blocks your agent's hot path, then retire the old service. Do not dual-write — diverging memory state across two systems is a harder problem than a clean cutover.
