LangGraph Python Tutorial 2026: Implementing Memory and State Management in AI Apps
LangGraph Python Tutorial 2026: Implementing Memory and State Management in AI Apps
Building smart AI apps is exciting, but how do they remember things? Imagine talking to someone who forgets everything you said after each sentence; that wouldn’t be very helpful, right? This guide will show you how LangGraph helps your AI apps remember things, handle what they know, and stay smart in 2026. You’ll learn all about langgraph memory state python 2026 in a way that’s easy to understand.
Why Your AI Needs a Good Memory
Think of your AI app as a friend. If your friend can’t remember past conversations, they won’t understand what you’re talking about next. For AI apps, this “memory” is called “state.” State is all the information an AI app knows at any given moment.
This information helps the AI make smart decisions and keep a smooth conversation going. Without remembering, every interaction would be like starting from scratch. That’s why good State architecture patterns are so important.
What is LangGraph and How Does it Help?
LangGraph is a clever tool that helps you build AI applications that have a flow, like a story. It lets you link different AI actions and tools together in a specific order. This “flow” means your AI can do many things in steps, like asking a question, then looking up information, and then giving you an answer.
The best part about LangGraph is how it manages the “memory” or “state” of your AI as it moves through these steps. It ensures that information passes correctly from one step to the next. You’ll see how langgraph memory state python 2026 makes this easy.
Understanding State in AI Applications
When we talk about “state” in AI, we mean all the important pieces of information your AI needs to do its job. For a chatbot, this might be the user’s name, their last question, or a preference they told the bot earlier. For a complex AI agent, it could be the results of a search, the current goal, or a plan it’s following.
Keeping track of this state is like writing down notes so you don’t forget important details. LangGraph gives you great tools to manage these notes automatically. This is key for any AI app that needs to act intelligently over time.
Getting Started with Basic Memory: The MemorySaver
LangGraph offers a simple way to give your AI a short-term memory called MemorySaver. This is like a notepad your AI uses during a single conversation or task. It remembers things as long as the app is running and doesn’t forget until you close the app.
The MemorySaver is perfect for quick tests or simple apps where you don’t need to keep information forever. It helps you understand the basic idea of langgraph memory state python 2026 without complex setups. Let’s see how MemorySaver implementation works.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
from langgraph.graph import StateGraph, END
from typing import TypedDict, Annotated, List, Union
import operator
# 1. Define your AI's 'memory' or 'state'
class AgentState(TypedDict):
messages: Annotated[List[str], operator.add]
step_count: int
# 2. Define a simple function that changes the state
def add_message(state: AgentState):
current_messages = state.get("messages", [])
new_message = "Hello from AI!"
return {"messages": current_messages + [new_message], "step_count": state.get("step_count", 0) + 1}
# 3. Build your LangGraph
workflow = StateGraph(AgentState)
workflow.add_node("step_one", add_message)
workflow.set_entry_point("step_one")
workflow.add_edge("step_one", END)
# 4. Compile the graph with a MemorySaver
from langgraph.checkpoint.sqlite import MemorySaver
memory = MemorySaver()
app = workflow.compile(checkpointer=memory)
# 5. Run the app and see the state change
print("--- First run ---")
inputs = {"messages": ["User: What's up?"], "step_count": 0}
config = {"configurable": {"thread_id": "user1"}}
result1 = app.invoke(inputs, config=config)
print(f"State after run 1: {result1}")
print("\n--- Second run with the same thread_id ---")
result2 = app.invoke({"messages": ["User: How are you?"]}, config=config)
print(f"State after run 2: {result2}")
# Let's inspect the memory directly (for demonstration)
# In a real app, you wouldn't usually access it this way,
# but it shows how MemorySaver keeps track.
print("\n--- State directly from MemorySaver (thread_id='user1') ---")
checkpoint = memory.get_tuple(config)
if checkpoint and checkpoint.checkpoint:
print(f"Current persisted state: {checkpoint.checkpoint['metadata']['global_state']}")
else:
print("No checkpoint found.")
In this example, the MemorySaver keeps track of messages and step_count for user1. When you run the app again with the same thread_id, it remembers the previous state. This is simple in-memory state management.
Moving Beyond Simple Memory: Persistent State
While MemorySaver is good for simple tasks, what happens if your computer turns off? All that important information stored in memory would disappear forever. For real-world AI apps, you need a way to save this “state” permanently. This is where checkpoint savers come in.
Checkpoint savers allow your AI to write its memory to a database or a file. This means even if your app crashes or restarts, it can pick up right where it left off. This is super important for long conversations or complex tasks that take time. It also helps with thread-level persistence, meaning different users or conversations can each have their own saved memory.
Implementing Persistent State with PostgreSQL checkpointer
PostgreSQL is a very popular and powerful database. It’s an excellent choice for saving your AI’s state because it’s reliable and can handle lots of information. Using a PostgreSQL checkpointer means LangGraph will automatically save your AI’s progress to a PostgreSQL database.
This way, your AI will never forget your conversation, even if you close the app and open it later. It’s a robust solution for langgraph memory state python 2026 applications that need to remember things over long periods.
Setting Up PostgreSQL for LangGraph
Before you can use PostgreSQL, you need to have it installed and running. You’ll also need a database and a user that LangGraph can connect with. If you’re unsure about setting up PostgreSQL, there are many guides online. Once it’s ready, you’ll install a Python library to connect to it.
1
2
# First, make sure you have the LangGraph and PostgreSQL adapter installed
pip install langgraph "psycopg[binary]"
Then, you can tell LangGraph to use it. You’ll need a connection string that tells LangGraph how to find your database. This string usually looks like postgresql+psycopg://user:password@host:port/database_name.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import os
from langgraph.graph import StateGraph, END
from typing import TypedDict, Annotated, List, Union
import operator
from langgraph.checkpoint.postgres import PostgresSaver
# Define your state again
class AgentState(TypedDict):
messages: Annotated[List[str], operator.add]
session_data: str
# Define a function that updates the state
def process_input(state: AgentState):
current_messages = state.get("messages", [])
last_user_message = current_messages[-1] if current_messages else "No message."
ai_response = f"AI received: '{last_user_message}'. Let's continue!"
return {"messages": current_messages + [ai_response], "session_data": "processed"}
# Build your LangGraph workflow
workflow = StateGraph(AgentState)
workflow.add_node("process", process_input)
workflow.set_entry_point("process")
workflow.add_edge("process", END)
# Set up the PostgreSQL checkpointer
# IMPORTANT: Replace with your actual PostgreSQL connection string
# It's best practice to load this from environment variables, not hardcode
PG_CONNECTION_STRING = os.getenv("LANGGRAPH_PG_CONNECTION_STRING", "postgresql+psycopg://user:password@localhost:5432/langgraph_db")
checkpointer = PostgresSaver.from_connection_string(PG_CONNECTION_STRING)
# Compile the graph with the PostgreSQL checkpointer
app_pg = workflow.compile(checkpointer=checkpointer)
# Run the app for a specific user (thread_id)
user_thread_id = "customer_alice_123"
config_alice = {"configurable": {"thread_id": user_thread_id}}
print(f"--- Running for {user_thread_id} (first interaction) ---")
inputs_alice = {"messages": ["User: I need help with my account."], "session_data": ""}
result_alice_1 = app_pg.invoke(inputs_alice, config=config_alice)
print(f"State after 1st run: {result_alice_1}")
# Simulate restarting the application or a new request from the same user
print(f"\n--- Running for {user_thread_id} (second interaction, app restarted) ---")
# When you invoke again with the same thread_id, LangGraph loads the last saved state
result_alice_2 = app_pg.invoke({"messages": ["User: What's the status of my order?"]}, config=config_alice)
print(f"State after 2nd run: {result_alice_2}")
# You can verify this in your PostgreSQL database by querying the langgraph_checkpoint table.
# You'll see entries for 'customer_alice_123'
This example shows how PostgresSaver keeps your AI’s memory safe in a database. Even if you stop and restart your Python program, the customer_alice_123 conversation will continue from where it left off. This is a powerful feature for reliable langgraph memory state python 2026 applications.
Another Option: MongoDB state storage
While PostgreSQL is great, sometimes you might prefer a NoSQL database like MongoDB. MongoDB is very flexible and good for data that doesn’t fit neatly into rows and columns. It’s also a strong choice for langgraph memory state python 2026 when your state schema might change a lot, or you need to store large, complex JSON objects.
Using MongoDB state storage with LangGraph means your AI’s memory will be saved as documents in a MongoDB collection. This can be very efficient and scalable for certain types of applications.
Setting Up MongoDB for LangGraph
Just like PostgreSQL, you’ll need MongoDB installed and running. You’ll also need to install the Python library for MongoDB:
1
2
# Install the LangGraph and MongoDB adapter
pip install langgraph pymongo
Then, you can set up the MongoDB checkpointer. You’ll need to provide the connection details for your MongoDB server.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import os
from langgraph.graph import StateGraph, END
from typing import TypedDict, Annotated, List, Union
import operator
from langgraph.checkpoint.mongodb import MongoDBSaver
# Define your state for this example
class ChatState(TypedDict):
chat_history: Annotated[List[str], operator.add]
user_settings: dict
# Define a node that adds to chat history and updates settings
def chat_node(state: ChatState):
current_history = state.get("chat_history", [])
last_message = current_history[-1] if current_history else "No message."
ai_response = f"AI replied to: '{last_message}'. How can I help further?"
# Simulate a setting update
current_settings = state.get("user_settings", {})
if "theme" not in current_settings:
current_settings["theme"] = "dark" # Set default theme
return {"chat_history": current_history + [ai_response], "user_settings": current_settings}
# Build the LangGraph workflow
workflow_mongo = StateGraph(ChatState)
workflow_mongo.add_node("chat_process", chat_node)
workflow_mongo.set_entry_point("chat_process")
workflow_mongo.add_edge("chat_process", END)
# Set up the MongoDB checkpointer
MONGO_CONNECTION_STRING = os.getenv("LANGGRAPH_MONGO_CONNECTION_STRING", "mongodb://localhost:27017/")
DB_NAME = "langgraph_checkpoints"
COLLECTION_NAME = "ai_states" # Optional, defaults to 'langgraph_checkpoint'
checkpointer_mongo = MongoDBSaver(MONGO_CONNECTION_STRING, db_name=DB_NAME, collection_name=COLLECTION_NAME)
# Compile the graph with the MongoDB checkpointer
app_mongo = workflow_mongo.compile(checkpointer=checkpointer_mongo)
# Run the app for a specific user (thread_id)
user_id_mongo = "chat_user_bob"
config_bob = {"configurable": {"thread_id": user_id_mongo}}
print(f"--- Running for {user_id_mongo} (first chat message) ---")
inputs_bob_1 = {"chat_history": ["User: Hi there, I need support!"], "user_settings": {}}
result_bob_1 = app_mongo.invoke(inputs_bob_1, config=config_bob)
print(f"State after 1st message: {result_bob_1}")
# Simulate another message from the same user, perhaps after app restart
print(f"\n--- Running for {user_id_mongo} (second chat message) ---")
result_bob_2 = app_mongo.invoke({"chat_history": ["User: Can you tell me about feature X?"]}, config=config_bob)
print(f"State after 2nd message: {result_bob_2}")
# You can check your MongoDB database to see the saved state for 'chat_user_bob'
# in the 'ai_states' collection of 'langgraph_checkpoints' database.
This demonstrates how MongoDBSaver can be used to store your AI’s conversational state and user-specific settings. The flexibility of MongoDB makes it a great choice for state schema design where the state might evolve.
Designing Your AI App’s State Schema
The “state schema” is like a blueprint for your AI’s memory. It defines what pieces of information your AI will remember and how they are organized. Good state schema design is super important because it makes your AI more reliable and easier to work with. Think about what your AI needs to know to be helpful.
For example, a simple chatbot might need to remember user_id, conversation_history, and current_topic. A more complex AI agent might need goals, tools_used, action_plan, and observations. Carefully planning your state schema helps your AI stay organized and makes handling state mutations much clearer. For more advanced schema design patterns, you can refer to our blog post on Advanced Data Modeling for AI State.
Example State Schema Considerations
| Field Name | Type | Description | Example Value |
|---|---|---|---|
conversation_id |
string | Unique ID for each chat session | chat-12345 |
messages |
list[str] | All messages exchanged, in order | ["User: Hi", "AI: Hello!"] |
current_goal |
string | What the AI is trying to achieve right now | Find movie recommendations |
search_results |
dict | Data from last search, if any | {"movies": ["Inception", "Matrix"]} |
user_preferences |
dict | User’s favorite settings (e.g., dark mode, language) | {"theme": "dark", "language": "en"} |
last_updated_time |
timestamp | When the state was last changed | 2026-01-15T10:30:00Z |
When designing your schema, always think about what data absolutely needs to be saved and what can be recreated. Keep it simple at first, and then add more fields as your AI app becomes smarter. This modular approach makes it easier to debug and extend your langgraph memory state python 2026 application.
Handling State Mutations and Updates
Once you have your state schema, your AI will constantly need to update this information. This process of changing the state is called “state mutation.” LangGraph makes handling state mutations very clear and controlled. Each step (node) in your graph can receive the current state, make changes, and then pass the updated state along.
It’s important to make sure these changes are done safely and predictably. You want to avoid situations where different parts of your AI try to change the same piece of information at the same time in conflicting ways. LangGraph’s use of Annotated and operator.add for lists, as shown in the examples, helps manage these updates gracefully.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
from langgraph.graph import StateGraph, END
from typing import TypedDict, Annotated, List, Union
import operator
# Define a state with a counter and a list of events
class TaskState(TypedDict):
task_description: str
progress_steps: Annotated[List[str], operator.add] # Use operator.add for lists
status: str
counter: Annotated[int, operator.add] # Use operator.add for numbers
# Node 1: Initialize the task
def initialize_task(state: TaskState):
if not state.get("task_description"):
return {"task_description": "New task: Analyze market trends",
"progress_steps": ["Task initialized."],
"status": "pending",
"counter": 1}
return state # Don't re-initialize if already set
# Node 2: Perform analysis step
def perform_analysis(state: TaskState):
if state["status"] == "pending":
print(f"Current progress: {state['progress_steps'][-1]}")
return {"progress_steps": ["Analysis started."],
"status": "in_progress",
"counter": 1}
return state
# Node 3: Generate report
def generate_report(state: TaskState):
if state["status"] == "in_progress":
print(f"Current progress: {state['progress_steps'][-1]}")
return {"progress_steps": ["Report being generated."],
"status": "reporting",
"counter": 1}
return state
# Node 4: Finalize task
def finalize_task(state: TaskState):
if state["status"] == "reporting":
print(f"Current progress: {state['progress_steps'][-1]}")
return {"progress_steps": ["Task completed successfully!"],
"status": "completed",
"counter": 1}
return state
# Define a conditional edge for flow control
def decide_next_step(state: TaskState):
if state["status"] == "pending":
return "perform_analysis"
elif state["status"] == "in_progress":
return "generate_report"
elif state["status"] == "reporting":
return "finalize_task"
else:
return END
# Build the LangGraph workflow
workflow_mutations = StateGraph(TaskState)
workflow_mutations.add_node("init", initialize_task)
workflow_mutations.add_node("perform_analysis", perform_analysis)
workflow_mutations.add_node("generate_report", generate_report)
workflow_mutations.add_node("finalize_task", finalize_task)
workflow_mutations.set_entry_point("init")
workflow_mutations.add_conditional_edges("init", decide_next_step)
workflow_mutations.add_conditional_edges("perform_analysis", decide_next_step)
workflow_mutations.add_conditional_edges("generate_report", decide_next_step)
workflow_mutations.add_edge("finalize_task", END)
# Use an in-memory saver for this example
from langgraph.checkpoint.sqlite import MemorySaver
memory_mutations = MemorySaver()
app_mutations = workflow_mutations.compile(checkpointer=memory_mutations)
# Simulate running the task in steps
thread_id_task = "market_analysis_project_X"
config_task = {"configurable": {"thread_id": thread_id_task}}
print("--- Starting Task Workflow ---")
# First invocation (will run init -> perform_analysis)
# We don't provide initial inputs beyond what's needed for the graph to start
initial_state = {"task_description": "", "progress_steps": [], "status": "", "counter": 0}
result_1 = app_mutations.invoke(initial_state, config=config_task)
print(f"After step 1: {result_1['progress_steps'][-1]}, Status: {result_1['status']}, Counter: {result_1['counter']}")
# Second invocation (will run generate_report)
# LangGraph loads the state from the previous run
result_2 = app_mutations.invoke({}, config=config_task) # No new inputs, just advance the state
print(f"After step 2: {result_2['progress_steps'][-1]}, Status: {result_2['status']}, Counter: {result_2['counter']}")
# Third invocation (will run finalize_task)
result_3 = app_mutations.invoke({}, config=config_task)
print(f"After step 3: {result_3['progress_steps'][-1]}, Status: {result_3['status']}, Counter: {result_3['counter']}")
# Fourth invocation (will do nothing as status is 'completed')
result_4 = app_mutations.invoke({}, config=config_task)
print(f"After step 4: {result_4['progress_steps'][-1]}, Status: {result_4['status']}, Counter: {result_4['counter']}")
# Inspect the final state in memory
checkpoint_final = memory_mutations.get_tuple(config_task)
if checkpoint_final and checkpoint_final.checkpoint:
final_state_from_memory = checkpoint_final.checkpoint['metadata']['global_state']
print(f"\nFinal state from MemorySaver for '{thread_id_task}': {final_state_from_memory}")
This example shows how operator.add helps handling state mutations for lists and numbers. Each node adds to the progress_steps list and the counter while updating the status. This is a clean way to manage changes in your langgraph memory state python 2026 applications.
Advanced State Management Techniques
As your AI apps grow, you might need more clever ways to manage their memory. LangGraph and its checkpointers provide a solid foundation for advanced patterns.
Versioning State
Imagine if you could go back in time and see what your AI knew at any point in a conversation. Versioning state means keeping different copies of your AI’s memory as it changes. This is incredibly useful for several reasons. It lets you understand how your AI arrived at its current understanding. It’s also a building block for powerful rollback mechanisms.
While LangGraph’s checkpointers save the latest state by default, their underlying databases can support full versioning. You can implement custom logic to store multiple checkpoints or leverage database features for this. This helps trace and debug complex AI behaviors.
Rollback Mechanisms
A “rollback” means going back to an earlier saved state. It’s like having an “undo” button for your AI’s brain. If your AI makes a mistake or gets into a confusing situation, you can simply roll it back to a previous, known-good state. This can prevent endless loops or incorrect actions.
With checkpointers like PostgreSQL checkpointer or MongoDB state storage, the ability to load a specific historical checkpoint (if your versioning supports it) means you can effectively implement rollback mechanisms. This adds a layer of safety and resilience to your langgraph memory state python 2026 applications.
Thread-Level Persistence
For AI apps that talk to many users at once, it’s crucial that each conversation remembers its own details. This is called thread-level persistence. You don’t want Alice’s conversation details getting mixed up with Bob’s. LangGraph handles this beautifully with thread_id.
When you use a checkpointer (like PostgreSQL or MongoDB), each unique thread_id saves its state separately. This means thousands of users can interact with your AI, and each interaction will be correctly remembered and continued. This is a core strength of langgraph memory state python 2026 for real-world applications.
Debugging State Issues in LangGraph
Even with the best planning, sometimes your AI might behave unexpectedly. This is where state debugging tools come in handy. Debugging state means looking closely at what your AI remembers at different points in its process. You need to understand why its memory changed the way it did.
LangGraph’s checkpointing system naturally helps with debugging. Since the state is saved, you can inspect the database directly to see the full context of a problem. You can also add special “debugging nodes” to your graph that print out the current state at critical points.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import pprint # For pretty printing dictionaries
# ... (previous setup for TaskState and a basic workflow) ...
# A simple debugging node
def debug_state_node(state: TaskState):
print("\n--- DEBUG INFO (Current State) ---")
pprint.pprint(state)
print("----------------------------------\n")
return state # Pass the state along unchanged
# Modify the workflow to include a debug node
workflow_debug = StateGraph(TaskState)
workflow_debug.add_node("init", initialize_task)
workflow_debug.add_node("perform_analysis", perform_analysis)
workflow_debug.add_node("debug_analysis", debug_state_node) # Add debug node here
workflow_debug.add_node("generate_report", generate_report)
workflow_debug.add_node("debug_report", debug_state_node) # And here
workflow_debug.add_node("finalize_task", finalize_task)
workflow_debug.set_entry_point("init")
workflow_debug.add_edge("init", "perform_analysis")
workflow_debug.add_edge("perform_analysis", "debug_analysis") # Link to debug node
workflow_debug.add_edge("debug_analysis", "generate_report") # Then continue
workflow_debug.add_edge("generate_report", "debug_report") # Link to another debug node
workflow_debug.add_edge("debug_report", "finalize_task") # Then continue
workflow_debug.add_edge("finalize_task", END)
# Use in-memory saver for simplicity in this debug example
app_debug = workflow_debug.compile(checkpointer=MemorySaver())
thread_id_debug = "debug_test_1"
config_debug = {"configurable": {"thread_id": thread_id_debug}}
print("--- Running Workflow with Debug Nodes ---")
# Invoke the graph. Each debug node will print the state at that point.
app_debug.invoke({}, config=config_debug)
This snippet shows how to insert a debug_state_node into your graph. This node simply prints the current state without changing it, giving you a clear snapshot of what your AI remembers at that specific moment. These custom state debugging tools are invaluable for understanding the flow of information in your langgraph memory state python 2026 applications. You can also set breakpoints in your code and step through each node’s execution using a standard Python debugger.
The Future of langgraph memory state python 2026
The world of AI is always changing, and LangGraph is constantly evolving. In 2026 and beyond, we can expect even more sophisticated State architecture patterns to emerge. This might include built-in support for more complex versioning state or even more intelligent ways to handle concurrent state updates. The focus will remain on making it easier for you to build powerful, reliable, and scalable AI applications.
As AI models become more capable, the importance of robust memory and state management will only grow. Staying updated with the latest LangGraph features and best practices for langgraph memory state python 2026 will be key to building truly groundbreaking AI experiences.
Conclusion
You’ve learned a lot about how to give your AI apps a good memory using LangGraph. From simple MemorySaver implementation to persistent storage with PostgreSQL checkpointer and MongoDB state storage, you now understand the tools to make your AI remember. We also covered the importance of state schema design, handling state mutations, and advanced ideas like versioning state and rollback mechanisms.
With these skills, you’re ready to build AI apps that are not just smart, but also remember and learn from past interactions. The journey of building intelligent AI applications with langgraph memory state python 2026 is an exciting one, and mastering memory and state is a crucial step. Go forth and create amazing things!
Leave a comment