Memory that outlives the conversation
A store is a saver for facts that outlive any one conversation, filed as JSON documents under a namespace and a key.
Last updated: 27 Sep, 2026 · LangChain 1.4
Memory that lives outside the thread
A checkpointer saves one conversation. Start a new thread and it begins empty. The video shows the other kind of memory through the Deep Agents store backend: a persistent key-value storage backed by a LangGraph store. The demo uses an InMemoryStore and a namespace. One thread asks the agent to create a file, and a second thread, thread_2, whose config gets a fresh thread_id from uuid.uuid4(), reads the same file, /notes/todo.txt, back. The store sits outside any one thread, so two sessions can both read it.
With InMemoryStore nothing goes to disk: each entry lives in memory, keyed under its namespace. The backend decides where the data physically lives. The state backend keeps it in one thread's LangGraph state, the file system backend on disk, and the store backend in the store, shared by every thread. An in-memory store is gone after a restart unless the storage is persisted. Long-term memory in LangChain uses the same store: facts the agent should know across every conversation with one person, such as their preferences or what they asked to be remembered, organised by namespace, for example one namespace per user.
Now the shop. Ravi told the shop once to leave parcels at the back door. That belongs to Ravi, not to any one conversation, so a new thread next week should still know it.
Pick one to watch it run, step by step.
The InMemoryStore API
from langgraph.store.memory import InMemoryStore
store = InMemoryStore()
store.put(("customers", "ravi"), "delivery", {"note": "..."}) # namespace, key, value
item = store.get(("customers", "ravi"), "delivery") # an item, or NonePutting and getting
The namespace ("customers", "ravi") works like a folder path, one folder per customer, and the key "delivery" names the document inside it. Save a note there and read it back. A folder with nothing under that key returns None.
from langgraph.store.memory import InMemoryStore
store = InMemoryStore()
store.put(("customers", "ravi"), "delivery", {"note": "leave it at the back door"})
item = store.get(("customers", "ravi"), "delivery")
print(item.key, item.value)
print(store.get(("customers", "mei"), "delivery"))delivery {'note': 'leave it at the back door'}
NoneThe customer and the orders
A tool can reach the store through its runtime. Start with the same Customer context class from Runtime context: who is asking, and the order data.
from dataclasses import dataclass
@dataclass
class Customer: # who is asking, passed as context
name: str
ORDERS = {"A17": "shipped on 3 March", "C40": "waiting for stock"}A tool that uses the store
runtime.store is the store you gave the agent. The tool writes down which order Ravi asked about and reads his delivery note. It labels the note as the customer's own instruction, so the model passes it on instead of telling Ravi to go to the back door himself.
from langchain.tools import ToolRuntime, tool
@tool
def lookup_order(order_id: str, runtime: ToolRuntime[Customer]) -> str:
"""Look up an order's shipping status by its id, such as A17."""
folder = ("customers", runtime.context.name) # this customer
runtime.store.put(folder, "last_order", {"order_id": order_id}) # write
note = runtime.store.get(folder, "delivery") # read note
status = f"{order_id} {ORDERS.get(order_id, 'is not an order we have')}."
if note: # the customer's own words
status += f" The customer's delivery instruction: {note.value['note']}."
return statusThe agent with a store
Give the agent the store, the context type, and a checkpointer. Seed the store with Ravi's note first.
from langchain.agents import create_agent
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.store.memory import InMemoryStore
from langchain.chat_models import init_chat_model
store = InMemoryStore()
store.put(("customers", "ravi"), "delivery", {"note": "leave it at the back door"})
agent = create_agent(init_chat_model("groq:openai/gpt-oss-120b", temperature=0), tools=[lookup_order], context_schema=Customer, # uses your GROQ_API_KEY
system_prompt="You are the support assistant for a small online shop. Answer in one or two short sentences, using only what the tools returned.",
checkpointer=InMemorySaver(), store=store)Looking up A17 with a saved note
Ask as Ravi. The delivery note comes out of the store, not the conversation.
ravi = Customer("ravi")
result = agent.invoke({"messages": [{"role": "user", "content": "Where is A17?"}]},
{"configurable": {"thread_id": "monday"}}, context=ravi)
print(result["messages"][-1].text)A17 was shipped on 3 March and should be left at the back door.
A new thread, the same customer
A different thread_id starts a fresh conversation, but the store is shared. Ravi's note is still there, and the last order is now C40.
result = agent.invoke({"messages": [{"role": "user", "content": "And C40?"}]},
{"configurable": {"thread_id": "friday"}}, context=ravi)
print(len(result["messages"]))
print(store.get(("customers", "ravi"), "last_order").value)4
{'order_id': 'C40'}What the store kept across threads
- A missing document returns
None, so Mei's folder givesNonefor a note only Ravi set. - The delivery note in Ravi's answer came out of the store, and the tool wrote A17 down as the order he asked about last.
- The Friday thread holds four messages, none from Monday: the checkpointer keeps threads apart. The store does not, so the note stays and the last order is now C40.
Thread vs store
| Thread (checkpointer) | Store | |
|---|---|---|
| Holds | One conversation | Facts across all conversations |
| Keyed by | thread_id | namespace + key |
| A new thread | Starts empty | Still has the facts |
| Read with | get_state | store.get |
Where long-term memory fits
- Remembering a customer's preferences from one visit to the next.
- Any fact that belongs to a user or account rather than a single chat.
store= and a tool that calls runtime.store raises at run time. The store has to be handed to the agent before a tool can read or write it.Related
- Previous: Trimming and removing messages
- Next: Semantic search in long-term memory
- Reference: Long-term memory
- Invoke as Mei and check that the answer has no delivery note.
- Print
[i.key for i in store.search(("customers", "ravi"))]. - Create the agent without
store=and read the error the tool raises.
Little by little, you're building something great.