
How to add persistent memory to a LangGraph agent with FishMem
August 23, 2026Guides

Map familiar operations, document semantic differences, replay representative traces, and preserve rollback until stored state and recall pass.
A migration between memory systems is not an import rename. Two APIs can both expose add, search, update, and delete while disagreeing about extraction, identity, temporal fields, filters, pagination, history, and when a write is considered complete.
The safe path begins with the deployed contract—not a current quickstart—and ends only when persisted state and downstream answers pass an observation window.
Record the mem0 SDK and service versions, hosting mode, vector backend, model configuration, custom prompts, graph or reranking features, default limits, and every field your application reads from responses. Capture representative requests and outputs before changing dependencies.
At minimum, inventory:
The contract in production may be older or more customized than the documentation you read today. Treat current documentation as a reference, not evidence of what your application actually deployed.
| Concern | Source question | FishMem decision |
|---|---|---|
| Outer tenancy | Which account or project owns the data? | Bind the authenticated project namespace; never trust it from the body |
| User and agent scope | Who should retrieve the record? | Map to user_id, agent_id, and run_id only when meanings match |
| Inference | Is the export already a durable fact or raw conversation? | Use infer=false for distilled records; evaluate inference separately |
| Time | Is a timestamp ingestion time, event time, or validity? | Preserve known meanings; never invent precision |
| History | Does update replace, append, or supersede? | Choose current-state and immutable-history behavior explicitly |
| Completion | When does the source call report success? | Deterministic writes complete synchronously; inferred Cloud writes return a durable event |
A mem0 export generally contains memory records, not the original conversation that produced them. Passing those records through another extraction model changes wording, drops detail, and makes it impossible to distinguish migration loss from product behavior.
Import the record content deterministically with infer=false, carry source identifiers in migration provenance, and preserve the original export outside FishMem until the observation window ends. If you also have raw conversations and want to compare a new inference policy, treat that as a separate experiment.
Each source record needs a durable migration status. A practical ledger contains:
Generate idempotency keys from a stable migration identity rather than a loop counter. A restarted importer should converge on the same destination records.
Create an isolated FishMem project and replay redacted user journeys. Compare more than search text:
Include cases with no relevant memory, conflicting facts, changed preferences, duplicate requests, missing metadata, and users with similar histories. A migration that only tests happy-path adds does not test retrieval or isolation.
During a shadow phase, keep the source system authoritative. Send the same query to FishMem, record both result sets, and compare the downstream decision without exposing FishMem output to the user. This reveals ranking and formatting differences before they affect production.
Do not require byte-identical context. Different systems may return different phrasing and order while supporting the same correct decision. Define required evidence, forbidden evidence, and expected answer behavior.
A rollback that depends on the destination system being healthy is not independent. Retain the source export, source-to-destination ledger, previous read path, and a defined way to reconcile writes made during the canary period.
Before retirement, export FishMem and test that the namespace can be restored into an empty target. This proves you can leave the destination as well as enter it.
A user_id may mean an end user, an account, or a conversation participant. Map the authorization meaning, not just the string.
Import timestamps may describe when a row was stored, not when the underlying fact became true. Keep them separate or leave event time unknown.
The migration changes content while claiming to preserve it. Import distilled records verbatim, then evaluate any new extraction policy on raw evidence.
If the application reports success when either backend succeeds, the two stores drift. Record both outcomes and define which one is authoritative at each phase.
FishMem is not affiliated with mem0 and does not claim universal drop-in compatibility. The migration surface is intentionally familiar, but semantic differences remain. Publish the versions and cases you verified, and describe everything else as untested.