Skip to main content
Compose sequences, parallel branches, conditional edges, and loops with the Graph API. For map-reduce fan-out and returning edges from nodes, see Use Send and Command. For node-level retries, timeouts, and caching, see Configure nodes.

Create a sequence of steps

Prerequisites This guide assumes familiarity with Define and update state.
This section shows how to build a sequential graph. Python also has an add_sequence shorthand for the same pattern. Add a sequence of nodes with add_node and add_edge on a StateGraph:
Or use the built-in shorthand .add_sequence:
LangGraph can add a persistence layer under the graph. State is checkpointed between nodes, so those nodes govern:They also shape how steps are streamed, and how the app is visualized and debugged in Studio.
The following end-to-end example builds a sequence of three steps:
  1. Populate a value in a key of the state
  2. Update the same value
  3. Populate a different value
First define the state. For how updates merge, see Process state updates with reducers. This example tracks two values:
Nodes are Python functions that read graph state and return updates. The first argument is always the state:
Each node update can name only the keys it changes.By default, that overwrites the previous value for those keys. Use reducers when updates should append or combine instead. See Process state updates with reducers.
Next, define a StateGraph on that state and wire the nodes. Use add_node and add_edge to populate the graph and define its control flow.
Specifying custom names Pass an explicit name as the first argument to add_node:
Note that:
  • add_edge takes node names. For bare functions, the default name is node.__name__.
  • The graph needs an entry point: add an edge from the START node.
  • The graph halts when there are no more nodes to execute.
Then compile the graph. Compile runs basic structure checks (for example, orphaned nodes). Pass a checkpointer here when the app needs persistence.
Invoke the graph:
Note that:
  • This invoke passes a value for one state key. Nodes can also write keys that were not in the input.
  • The first node overwrites the value that was passed in.
  • The second node updates that value.
  • The third node populates a different key.
Built-in shorthand langgraph>=0.2.46 includes a built-in short-hand add_sequence for adding node sequences. You can compile the same graph as follows:

Create branches

Parallel node execution speeds up graph runs. LangGraph fans out and fans in with standard edges and conditional_edges. The following examples build branching dataflows. For map-reduce fan-out to dynamic targets, see Use Send and Command.

Run graph nodes in parallel

This example fans out from Node A to B and C, then fans in to D. The state uses a reducer so values accumulate for that key instead of overwriting. For lists, that means concatenating the new list onto the existing list. See Process state updates with reducers.
With the reducer, you can see that the values added in each node are accumulated.
In the above example, nodes "b" and "c" are executed concurrently in the same superstep. Because they are in the same step, node "d" executes after both "b" and "c" are finished.Importantly, updates from a parallel superstep may not be ordered consistently. If you need a consistent, predetermined ordering of updates from a parallel superstep, you should write the outputs to a separate field in the state together with a value with which to order them.
LangGraph runs nodes in supersteps. Parallel branches in a superstep run concurrently, but the superstep is transactional: if any branch raises, none of that superstep’s updates apply to state.With a checkpointer, results from successful nodes in a completed superstep are saved and do not repeat when the run resumes.For flaky work such as unreliable API calls, use either:
  1. Ordinary try / except (or equivalent) inside the node.
  2. A RetryPolicy on the node so LangGraph retries selected exceptions. Only failing branches retry, so successful siblings are not re-run.
Together, these keep parallel execution while you control how failures are handled. For a full guide, see Fault tolerance.
Set max concurrency Pass max_concurrency as a top-level config key (not under configurable) when invoking the graph. See RunnableConfig.

Defer node execution

Deferring node execution delays a node until all other pending tasks are completed. This matters when branches have different lengths, which is common in map-reduce workflows. The parallel example above fans out and fans in when each path is one step. Add a node "b_2" on the "b" branch so the paths have unequal length. Node d uses defer so it waits for the longer branch:
Nodes "b" and "c" run concurrently in the same superstep. defer=True on node d keeps it from running until all pending tasks finish, so "d" waits for the full "b" branch. When every branch always runs, you can wait with a list-form edge instead of defer=True. add_edge also accepts a list of start nodes. This is not shorthand for separate add_edge calls; the two forms behave differently:
  • A list of start nodes runs d once, after all of the listed nodes have completed. If one of them never runs (for example, a conditional edge does not select its branch), d never runs and no error is raised. State updates from branches that did complete remain in the graph state, but d does not consume them.
  • Separate edges run d once per superstep in which any incoming branch completes. With branches of equal length, that is a single run; with branches of different lengths, d runs more than once.
  • Separate edges with defer=True (the pattern in the example above) run d once, after every selected branch has completed, whether the fan-out selected all of the branches or only some of them.
defer=True postpones the node until no tasks are pending anywhere in the graph, not only in the branches that feed it. A Send addressed to the node still invokes it separately.

Conditional branching

Route to different nodes at runtime from state. Node a updates state, then a conditional edge chooses b or c: Dashed edges are conditional routes. If your fan-out should vary at runtime based on the state, you can use add_conditional_edges to select one or more paths using the graph state. See the following example, where node a generates a state update that determines the next node.
Your conditional edges can route to multiple destination nodes. For example:

Create and control loops

A loop needs a way to stop. The usual pattern is a conditional edge that routes to END when a termination condition is met. You can also set a recursion limit when invoking or streaming. The limit is the number of super-steps allowed before LangGraph raises an error. See the recursion limit concept. The following examples use a simple looping graph. Node a either continues to b (which returns to a) or exits: Dashed edges are conditional routes.
To catch GraphRecursionError after the limit is hit, see Impose a recursion limit. To route to a completion path before the limit, see Handle recursion with RemainingSteps.
Add a conditional edge that encodes the termination condition:
To control the recursion limit, specify "recursion_limit" in the config. This will raise a GraphRecursionError, which you can catch and handle:
Define a graph with a simple loop. A conditional edge implements the termination condition.
This architecture is similar to a ReAct agent in which node "a" is a tool-calling model, and node "b" represents the tools. The route conditional edge ends the run after the "aggregate" list passes a threshold length. When you invoke the graph, it alternates between nodes "a" and "b" until that condition is met.

Impose a recursion limit

When a termination condition is not guaranteed, set the graph’s recursion limit. LangGraph raises GraphRecursionError after that many supersteps. Catch and handle the exception:
A more complex loop fans out one step into two nodes:Dashed edges are conditional routes from a.
This graph is a loop of supersteps: Node A, then B, then C and D concurrent, then back to A. The list-form edge waits for both "c" and "d" before returning to "a". For how list-form edges differ from separate edges into the same node, see Defer node execution.Invoking without a recursion limit completes two full laps before the termination condition:
With the recursion limit set to four, only one lap completes because each lap is four supersteps:

Access and handle the recursion counter

Nodes can read the current step from run metadata. Use that to react before the limit is hit.

Handle recursion with RemainingSteps

RemainingSteps is a Python-only managed value for how many steps remain before the recursion limit. Use it to route to a completion path before LangGraph raises GraphRecursionError:
Handle the limit inside the graph with RemainingSteps, or catch GraphRecursionError outside the graph: Related metadata keys include langgraph_node, langgraph_triggers, langgraph_path, and langgraph_checkpoint_ns.

Async

Async helps when IO-bound work can run concurrently. To convert a sync graph to async:
  1. Define nodes with async def instead of def.
  2. Use await for async calls inside those nodes.
  3. Invoke with .ainvoke or .astream.
Many LangChain objects implement the Runnable protocol, which has async variants of the sync methods. See the streaming guide for async streaming examples.

See also