What is .compile()?
.compile() is the final step in building a LangGraph StateGraph: it validates the graph structure, resolves the state type, and returns a CompiledStateGraph — a Runnable you can invoke, stream, or batch like any other LangChain component. Until .compile() is called, the graph is a mutable builder object; modifying it after compilation raises an error.
Compilation performs several structural checks: it verifies that all edge targets are registered nodes, that START has at least one outgoing edge, that END is reachable from every branch, and that the state schema is a valid TypedDict or Pydantic model. These checks surface configuration mistakes at startup rather than mid-execution. The checkpointer parameter is where multi-turn state persistence lives: passing a MemorySaver() stores graph state in memory between invocations keyed by a thread_id; passing a PostgresSaver or SqliteSaver persists state across process restarts. Without a checkpointer, every graph.invoke() call starts with a fresh state.
The interrupt_before and interrupt_after parameters let you pause execution mid-graph for human-in-the-loop approval workflows. The graph saves a checkpoint at the interrupt point and waits for a resume call — graph.invoke(None, config) — with the same thread_id. Compiled graphs are reusable and thread-safe: compile once at application startup, then invoke concurrently from multiple threads or async tasks without rebinding.
Use Cases
- • Finalize workflows
- • Enable checkpointing
- • Create executable graphs
- • Prepare for invocation
- • Add persistence
- • State management
Key Features
- ✓ Graph finalization
- ✓ Checkpointing support
- ✓ Runnable interface
- ✓ Invoke-able
- ✓ State persistence
- ✓ Flexible backends
When NOT to Use
You must compile before invoking any StateGraph — there is no alternative. Rebuild and recompile if you need to change graph structure after compilation.
Notes
Compile once at startup — not inside request handlers
.compile() validates the entire graph structure and is comparatively expensive. Do it at module level or in an application startup hook. Calling it inside a request handler adds latency to every request and negates the thread-safety benefit of reusing a single compiled graph.
thread_id is required when using a checkpointer
Passing a checkpointer without a thread_id in the invocation config raises a ValueError at runtime. Always include config={"configurable": {"thread_id": "some-unique-id"}} in every invoke/stream call when the graph was compiled with a checkpointer.
interrupt_before pauses — it does not cancel
After an interrupt_before, the graph checkpoint is saved and execution halts. To resume, call graph.invoke(None, config) with the same thread_id — passing None as input resumes from the saved checkpoint. Passing a new input dict restarts the graph from the beginning.
Subgraphs must be compiled before adding as nodes
Each subgraph (a nested StateGraph) must be independently compiled before being registered as a node in the parent graph. Passing an uncompiled StateGraph as a node raises a validation error at parent compile time, not at runtime.
Method Signature
graph = builder.compile(
checkpointer=None,
interrupt_before=None,
interrupt_after=None,
)
Parameters
| Parameter | Type | Required | Purpose |
|---|---|---|---|
| checkpointer | BaseCheckpointSaver | None | No | Checkpoint storage for state persistence across turns |
| interrupt_before | list[str] | None | No | Node names to pause before for human-in-the-loop |
| interrupt_after | list[str] | None | No | Node names to pause after execution |
Return Value
Type:
CompiledStateGraph
Description:
Compiled graph as a Runnable
Example Output:
graph = builder.compile()
Code Examples
Compile with MemorySaver for multi-turn memory
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import MemorySaver
from typing import TypedDict
class State(TypedDict):
messages: list
def chat_node(state):
return {"messages": state["messages"] + ["response"]}
builder = StateGraph(State)
builder.add_node("chat", chat_node)
builder.add_edge(START, "chat")
builder.add_edge("chat", END)
checkpointer = MemorySaver()
graph = builder.compile(checkpointer=checkpointer)
config = {"configurable": {"thread_id": "user-42"}}
result = graph.invoke({"messages": ["Hello"]}, config)
Human-in-the-loop with interrupt_before
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import MemorySaver
from typing import TypedDict
class State(TypedDict):
draft: str
approved: bool
def write_draft(state):
return {"draft": "This is my draft content"}
def publish(state):
return {"draft": state["draft"] + " [PUBLISHED]"}
builder = StateGraph(State)
builder.add_node("write", write_draft)
builder.add_node("publish", publish)
builder.add_edge(START, "write")
builder.add_edge("write", "publish")
builder.add_edge("publish", END)
# Pause before publish for human review
graph = builder.compile(
checkpointer=MemorySaver(),
interrupt_before=["publish"],
)
config = {"configurable": {"thread_id": "draft-1"}}
graph.invoke({"draft": "", "approved": False}, config)
# Graph paused — human reviews state["draft"] here
# Resume after approval:
graph.invoke(None, config)
Persistent state with SqliteSaver across restarts
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.sqlite import SqliteSaver
from typing import TypedDict
class State(TypedDict):
count: int
def increment(state):
return {"count": state["count"] + 1}
builder = StateGraph(State)
builder.add_node("inc", increment)
builder.add_edge(START, "inc")
builder.add_edge("inc", END)
# Persist state across process restarts
with SqliteSaver.from_conn_string("checkpoints.db") as saver:
graph = builder.compile(checkpointer=saver)
config = {"configurable": {"thread_id": "session-1"}}
result = graph.invoke({"count": 0}, config)
print(result["count"]) # 1
result = graph.invoke(None, config) # resume
print(result["count"]) # 2
Common Mistakes
❌ builder.invoke(input) # Must compile first
✅ graph = builder.compile(); graph.invoke(input)
Related LangChain References
Browse the full LangChain API reference index to explore more classes, methods, and decorators, or start with the LangChain introduction tutorial for end-to-end context on building with .compile() and the wider framework.
.compile() FAQ
What does .compile() do in LangChain?
Compile the graph for execution. .compile() is the final step in building a LangGraph StateGraph: it validates the graph structure, resolves the state type, and returns a CompiledStateGraph — a Runnable you can invoke, stream, or batch like any other LangChain component. Until .compile() is called, the graph is a mutable builder object; modifying it after compilation raises an error. Compilation performs several structural checks: it verifies that all edge targets are registered nodes, that START has at lea…
Which LangChain classes support .compile()?
.compile() is available on StateGraph. Pin your installed LangChain version and verify the method exists in that release before deploying.
When should I use .compile()?
Use .compile() when your LangChain chains, agents, or pipelines need the behavior described in this guide.
What does .compile() return?
.compile() returns a CompiledStateGraph. Compiled graph as a Runnable
Does .compile() have an async equivalent?
.compile() does not have a documented async variant. Avoid .compile() You must compile before invoking any StateGraph — there is no alternative. Rebuild and recompile if you need to change graph structure after compilation.
Where can I explore more LangChain API reference pages?
Open the LangChain API reference index on DevShelfHub to browse classes, methods, and decorators, each with runnable examples, parameters, common mistakes, and cross-links.