DEV Community

Cover image for A Beginner’s Guide to Dynamic Routing in LangGraph with Command()

A Beginner’s Guide to Dynamic Routing in LangGraph with Command()

When you build agents, not every request should follow the same path. Some inputs require tools, others require reasoning, and some simply need a quick response. Hard-coding all these paths quickly becomes messy. This is where dynamic routing comes in.

Dynamic routing means your graph decides what to do next at runtime, based on the current state. Instead of fixed edges that always lead to the same node, the graph can change direction depending on user intent, tool results, or intermediate reasoning.

LangGraph supports this kind of flexibility naturally, but the real enabler is the Command() API. With Command(), a node can explicitly tell the graph which node to run next and, optionally, update the state at the same time. You’re no longer just returning data; you’re returning instructions.

Think of Command() as giving your node a voice. Instead of silently handing off control, it can say, “Go here next,” “Stop now,” or “Route this to a different path.” That’s the foundation of dynamic routing in LangGraph, and once you understand it, your graphs become far more expressive and intelligent.

What Is Dynamic Routing in LangGraph?

Dynamic routing is the idea that your graph does not have to follow a fixed path. Instead of always moving from Node A to Node B, the next step can change at runtime based on what just happened.

In LangGraph, this means your agent can look at the current state, make a decision, and then choose where to go next. One user input might lead to a search node, another might trigger a tool call, and a third might end the conversation entirely. The flow adapts as it runs.

This is different from static routing, where edges are defined upfront and the graph always follows the same structure. Static routing is predictable, but limited. Dynamic routing is flexible, expressive, and much closer to how real agents behave.

LangGraph supports dynamic routing through the Command() object. Instead of returning just state updates, a node can return instructions that tell the graph exactly what to do next. This is what allows your agent to branch, reroute, loop, or exit intelligently, all at runtime.

Once you understand this concept, you stop thinking of LangGraph as a pipeline and start seeing it as a decision-making system.

How Command() Enables Dynamic Routing

This is where things get interesting.

In LangGraph, Command() is what allows a node to decide what happens next at runtime. Instead of relying on predefined conditional edges, a node can return a Command that explicitly tells the graph which node to run next and what state updates to apply.

Think of Command() as the node saying, “I’ve looked at the situation, and this is where we should go.”

When a node returns a Command, it can specify two important things. First, the next node to jump to. Second, any state updates that should be applied before moving on. This makes routing flexible, expressive, and easy to reason about.

What makes this powerful is that the decision logic lives inside the node itself. The node can inspect user input, model output, tool results, or any part of the state, and then dynamically choose the next step. No extra edge definitions. No complex routing tables. Just clear intent.

Dynamic routing with Command() shines when your agent needs to adapt on the fly. Maybe the user asks a follow-up question, maybe a tool call fails, or maybe the model decides it needs more information before continuing. Instead of forcing all possibilities into static edges, Command() lets your graph respond naturally.

At this point, LangGraph stops feeling like a rigid workflow engine and starts behaving like a living system that can change direction when needed.

Command(): The Engine Behind Dynamic Routing

In LangGraph, Command() is what allows a node to decide what happens next at runtime. Instead of relying only on pre-defined edges, Command() lets a node return instructions that tell the graph both where to go next and how to update state in one move.

At a high level, a Command contains:

  • the next node (or nodes) the graph should execute
  • the state updates that should be applied before moving forward

This means routing decisions are no longer fixed in the graph structure alone. They can be made dynamically, based on logic, tool results, or LLM output inside the node itself.


How Command() Enables Dynamic Routing

With Command(), routing logic lives inside the node function. A node can inspect the current state, make a decision, and return a Command that tells the graph exactly what to do next.

Here’s what happens when a node returns a Command:

  • the node evaluates the current state
  • It decides which node should run next
  • It updates the state if needed
  • The graph immediately follows the instruction

Because state updates and routing happen together, the flow stays predictable and clean. There’s no need for extra router nodes or complex conditional edges.

A Simple Example: Routing Based on User Intent

Let’s make this real with a small example.

We’ll build a router node that looks at user intent and decides where the graph should go next.

The idea

A user sends a message.

If the message looks like a question, we go to a question handler.

If it looks like a command, we go to a command handler.

The routing decision happens inside the node using Command().


Example Code

from langgraph.graph import StateGraph
from langgraph.types import Command

def router(state):
    text = state["input"].lower()

    if "how" in text or "what" in text:
        return Command(
            goto="question_node",
            update={"intent": "question"}
        )

    return Command(
        goto="command_node",
        update={"intent": "command"}
    )

def question_node(state):
    return {"response": "This looks like a question."}

def command_node(state):
    return {"response": "This looks like a command."}

graph = StateGraph()

graph.add_node("router", router)
graph.add_node("question_node", question_node)
graph.add_node("command_node", command_node)

graph.set_entry_point("router")

app = graph.compile()

Enter fullscreen mode Exit fullscreen mode

What’s happening here

  • The router node inspects the user input.
  • Instead of returning plain state, it returns a Command.
  • The goto field tells LangGraph which node to run next.
  • The update field safely updates the shared state at the same time.
  • The graph follows the instruction immediately, no conditional edges needed.

This is dynamic routing in its simplest form.

The decision lives inside the node, and the graph just follows orders.


Why this matters

With Command():

  • routing logic stays close to the reasoning
  • graphs become easier to read
  • dynamic flows feel natural, not forced

Once you understand this pattern, you can build agents that adapt on the fly without turning your graph into a maze of conditionals.

Best Practices for Dynamic Routing with Command()

  • Keep routing logic simple and easy to reason about. A node should decide where to go next based on clear signals, not complex chains of conditions.
  • Separate decision-making from heavy computation. Let one node focus on choosing the route, and let downstream nodes do the actual work.
  • Always update state intentionally. Only include the data the next node needs to continue correctly.
  • Use meaningful node names. This makes your routing logic easier to read, debug, and visualize.
  • Visualize your graph early. Dynamic routing becomes much clearer when you can see the possible paths your graph can take.

Dynamic routing is what turns a LangGraph app from a fixed pipeline into a truly intelligent system. With Command(), a node can make decisions, update state, and choose the next step all at once — cleanly and explicitly.

Instead of hardcoding paths or relying on fragile conditionals, you let each node say, “Here’s what I learned, and here’s where we should go next.” That clarity is what makes LangGraph powerful, predictable, and scalable.

Once you understand Command(), you stop thinking in straight lines and start designing flows that adapt naturally to user intent and runtime context.

And that’s when your graphs really come alive

Top comments (0)