Best AI Memory for LangGraph (2026)
LangGraph's checkpointer handles state inside a thread. It doesn't handle memory across threads, across users, or anything you'd want to recall by meaning. Six ways to add real memory to LangGraph — built-in, hosted, OSS — evaluated honestly.
Why this is two questions, not one
LangGraph has two memory primitives, and they answer different problems. Understanding the split is the start of picking the right tool.
- Checkpointer (
InMemorySaver,SqliteSaver,PostgresSaver) — persists the agent's state graphwithin a thread, so you can pause and resume a long-running agent run. It's session memory, not knowledge memory. Cannot recall by meaning. Cannot share across threads. - Store (
InMemoryStore,PostgresStore, LangGraph Cloud's managed store) — a key-value namespace per thread/user, with optional vector indexing. Cross-thread memory if you wire it that way. You bring your own embeddings, your own schema, your own entity extraction.
The Store is the closer cousin to what hosted memory layers ship — but it's a primitive, not a product. You still decide what to store, how to retrieve it, how to handle contradictions, how to scope per user. The hosted layers below answer those questions out of the box.
The quick answer
If you want a hosted memory layer that works alongside LangGraph's checkpointer (without replacing it): Ricord. If you're comfortable building on top of LangGraph's Store primitive and wiring your own entity extraction: LangGraph Store. If retrieval quality is your competitive edge: Mem0 OSS. The full matrix is below.
The decision matrix
Nine criteria, six options. The two LangGraph built-ins (Checkpointer and Store) are evaluated separately because they answer different problems.
| Criterion | Ricord | Mem0 | Letta | Cognee | Checkpointer | Store |
|---|---|---|---|---|---|---|
| Persists state within a thread | ||||||
| Persists memory across threads | ||||||
| Persists memory across users (multi-tenant) | DIY | DIY namespace | ||||
| Semantic recall (vector or graph) | Vector only, BYO embeddings | |||||
| Entity extraction + conflict resolution | Manual | |||||
| Browsable wiki of what was learned | ||||||
| Hard delete (GDPR) | DIY | Delete thread | DIY | |||
| Cross-client (same memory from Claude Desktop / Cursor) | API only | |||||
| Cost (smallest tier with memory features) | $15/mo annual | $249/mo for graph | Self-host + LLM | $0 OSS / self-host | $0 (built in) | $0 OSS or LangGraph Cloud |
Slot-by-slot — which fits your LangGraph build
If you only need state inside a thread
Checkpointer alone(PostgresSaver in prod, SqliteSaver in dev) is enough. Your agent pauses + resumes cleanly. There's no "memory" problem because there's no cross-session knowledge.
If you want cross-thread memory and you have engineers
Store + your own entity-extraction layer. The Store gives you key-value persistence with optional vector search. Layer your own extraction prompt, your own contradiction handling, your own namespace-per-user logic. This is the most common production pattern in LangGraph apps today — and the one teams come to regret around month three when the contradiction handling gets brittle.
If you want hosted memory that drops into LangGraph
Ricordworks alongside the Checkpointer without replacing it. The Checkpointer keeps doing thread-state persistence; Ricord handles knowledge memory (entities, facts, contradictions, wiki). Inside a node, you call Ricord's API to save and recall:
from langgraph.graph import StateGraph
import requests, os
RICORD = "https://api.ricord.ai/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['RICORD_API_KEY']}"}
def recall_node(state):
r = requests.get(f"{RICORD}/memories/recall",
headers=HEADERS,
params={"user_id": state["user_id"], "query": state["input"], "k": 5})
return {"context": [m["content"] for m in r.json()["hits"]]}
def save_node(state):
requests.post(f"{RICORD}/memories",
headers=HEADERS,
json={"user_id": state["user_id"], "content": state["new_fact"]})
return {}
# Wire into your graph
graph = StateGraph(MyState)
graph.add_node("recall", recall_node)
graph.add_node("agent", agent_node)
graph.add_node("save", save_node)
graph.add_edge("recall", "agent")
graph.add_edge("agent", "save")If you're building an agent product and want OSS memory
Mem0 OSS(Apache 2.0) is the cleanest fit alongside LangGraph — Python-first, well-documented, modifiable. You'll spend real time on the production- grade work (conflict resolution, multi-tenant, hard delete). Worth it if retrieval is your product's edge. When OSS wins →
If your agent framework is itself the value-add
Lettais an agent runtime AND a memory layer in one. If your product is shipping a custom agent runtime, Letta gives you both pieces with one architectural decision. Less flexible than LangGraph though — Letta has opinions LangGraph doesn't.
If you need extraction-pipeline depth + OSS
Cognee (AGPL-3) is the right pick. The extraction pipeline is configurable in ways Ricord and Mem0 hide. Be aware of the AGPL license implications for commercial products. Cognee details →
Why Ricord wins for most LangGraph builders
- Works alongside Checkpointer, doesn't replace it. Two clean concerns: LangGraph handles thread state, Ricord handles knowledge memory. No re-architecture.
- Entity extraction + conflict resolution out of the box. The two problems LangGraph Store forces you to solve yourself, solved at ingest by the hosted layer.
- Per-user scoping is a parameter, not an architecture. Pass
user_idto save/recall calls; the layer handles isolation. No namespace prefix management in your graph nodes. - Cross-client memory.The same memory your LangGraph backend writes is reachable from Claude Desktop, Cursor, Codex via Ricord's MCP server. Useful if your agent has a developer-facing surface alongside the production deployment.
Getting started
Pick the slot. If it's Ricord-alongside-Checkpointer, the Python snippet above is your starting point. If it's Store, follow LangGraph's docs and plan the extraction-layer engineering as a quarter of work.
pip install requests # Get an API key at https://ricord.ai/login?signup=true export RICORD_API_KEY=rc_live_... # Drop the recall_node + save_node into your StateGraph