LangGraph Agent Memory: Threads, Stores, and Persistence
LangGraph separates thread state from memory shared across runs. Here is how each layer works, how to test recall and correction, and how to keep durable project context outside the graph runtime.
Updated 6 min read
LangGraph gives agents two distinct memory layers: thread state, which lasts for a single run on a single thread, and a cross-thread store, which persists across runs and threads. Knowing which layer to use for each kind of information is the main decision in LangGraph agent memory design.
Thread state is convenient but transient. The cross-thread store requires a checkpointer and explicit reads and writes, but it is the only layer that survives between runs. Tools like fenbs keep the project brief, the standing rules, and the lessons the team has learned outside the graph entirely, so they are available to any connected assistant regardless of which LangGraph version or checkpointer is in use.
Thread state: what it is and when it disappears
Thread state is the state object that flows through a LangGraph graph during a single invocation. Nodes read from it and return updates to it. When the graph finishes, thread state is no longer accessible unless a checkpointer has saved it.
Without a checkpointer, every graph invocation starts with a blank state object. This is fine for stateless workflows where each run is independent. For conversational agents or multi-step pipelines where the agent must remember what it did in the previous run, a checkpointer is required from the start.
Checkpointers: persisting thread state between runs
A checkpointer saves the state of a thread after each node execution. LangGraph ships with a SQLite checkpointer for local development and a PostgreSQL checkpointer for production. Pass the checkpointer to the graph when you compile it, and pass a thread ID when you invoke the graph. The checkpointer loads the last saved state for that thread ID at the start of each run.
Thread ID is the key. Two invocations with the same thread ID share state through the checkpointer. Two invocations with different thread IDs start from separate state. Use a stable, meaningful thread ID tied to the user or the project, not a random ID generated on each run. A random ID means each run starts fresh, even with a checkpointer configured.
The cross-thread store: memory across multiple threads
The LangGraph store is a separate layer designed for memory that spans threads and users. While a checkpointer keeps the conversation history for one thread, the store keeps facts that any thread may read and update: user preferences, project summaries, learned lessons. The store is queried explicitly inside a node using a namespace and a key.
LangGraph's in-memory store is not persistent. For production use, connect a backend store: LangGraph Platform provides a managed option, and you can implement the BaseStore interface for your own backend. Verify the persistence of your chosen backend before relying on it for long-running work. See how to build agent memory for a comparison of backend options.
Keep project context beyond the graph runtime
A LangGraph checkpointer or store holds operational memory for the agent's graph. The shared project record, the team's decisions, and the lessons learned from earlier runs belong in fenbs, where they are readable by any connected assistant and any team member. Connect your assistant from /integrations so it reads fenbs context before the graph starts.
Create a free accountFree for one person · No credit card · Works with Claude, ChatGPT, Cursor and more
Testing recall across runs
Run a three-step recall test after setting up your checkpointer and store.
- Run the graph once with a stable thread ID. Confirm it writes at least one fact to the store and saves thread state through the checkpointer.
- Terminate the process and restart it from scratch, with no in-memory state.
- Run the graph again with the same thread ID. Confirm it loads the previously saved thread state and reads the previously stored fact before doing any new work.
If step three returns empty results, the checkpointer or store is not using a persistent backend. Check whether you are using the in-memory checkpointer (ephemeral) or the SQLite/PostgreSQL one (persistent). If you are using a persistent backend and the results are still empty, verify that the thread ID is the same in both runs. For more on LangGraph memory patterns, see what is agent memory.
Correcting stored facts
The store's put method overwrites an existing entry at the same namespace and key. To correct a stored fact, write a new value at the same location. The old value is replaced, not appended. If you need to preserve the history of corrections, use an append-only design: write each version as a new entry with a timestamp, and read back the most recent one.
Assign correction authority deliberately. If an agent can overwrite any store entry, one bad run can corrupt memory that took many sessions to build. Consider writing corrections through a node that checks the existing value and requires a confidence threshold or a human approval step before overwriting. See agent memory vs RAG for a comparison of retrieval and correction strategies.
How to do this with fenbs
Use LangGraph's checkpointer for thread state and the store for operational cross-thread memory. Use fenbs for the project context that needs to travel across tools, sessions, and team members.
- Create a free account and add your project to fenbs. Record the standing rules and current tasks.
- Connect your assistant from /integrations. Add a fenbs context-read step at the start of your LangGraph graph.
- Configure a persistent checkpointer: SQLite for local development, PostgreSQL for production.
- Add a cross-thread store with a persistent backend for facts that need to survive thread boundaries.
- Before each graph session ends, ask the assistant to save progress in fenbs so the next session knows where to start.