Code Intermediate medium · 5 min

draw_mermaid_png(): visual graph export

What you will learn
Export your compiled LangGraph as a PNG diagram to visualize node connections and control flow.

Why this matters

You need to understand your graph's structure: especially in production debugging, code reviews, and documentation. A visual export catches routing bugs and missing edges that text inspection misses. It's also the fastest way to explain your agentic architecture to non-engineers.

Skip if: When your graph is trivial (3 nodes or fewer, linear flow), visualization adds no value. Also skip it if you're iterating rapidly in development: wait until the graph stabilizes. Do not use this for real-time monitoring; it's a static export, not a live dashboard.

Explanation

What it is: draw_mermaid_png() is a method on compiled LangGraph graphs that exports the graph structure as a PNG image file. It introspects your nodes, edges, and control flow, then generates a Mermaid diagram and renders it.

How it works mechanically: When you call graph.compile().draw_mermaid_png(), LangGraph walks your StateGraph's topology: collecting node names, edge destinations, and conditional branches. It converts this to Mermaid flowchart syntax, then uses a Mermaid renderer (via an external service or local renderer) to produce a PNG. The method writes the file to disk at the path you specify.

When to use it: Call this after you've finalized your graph structure but before deployment. Use it in unit tests to assert graph topology hasn't changed, in documentation generators to auto-create architecture diagrams, and in debugging sessions when edge routing feels wrong.

Analogy

It's like exporting a circuit diagram from CAD software: the diagram doesn't run anything, but it shows you exactly how components connect so you can verify correctness before manufacturing.

Code

python
import os
from typing import TypedDict
from langgraph.graph import StateGraph, START, END

class State(TypedDict):
    message: str
    processed: bool

def node_a(state: State) -> State:
    return {**state, "message": f"Node A: {state['message']}"}

def node_b(state: State) -> State:
    return {**state, "message": f"Node B: {state['message']}"}

def router(state: State) -> str:
    if len(state["message"]) > 10:
        return "node_b"
    return "end"

def node_c(state: State) -> State:
    return {**state, "processed": True}

graph = StateGraph(State)
graph.add_node("node_a", node_a)
graph.add_node("node_b", node_b)
graph.add_node("node_c", node_c)

graph.add_edge(START, "node_a")
graph.add_conditional_edges("node_a", router, {"node_b": "node_b", "end": END})
graph.add_edge("node_b", "node_c")
graph.add_edge("node_c", END)

compiled = graph.compile()
compiled.draw_mermaid_png(output_file_path="graph.png")
print("Graph exported to graph.png")
Output
Graph exported to graph.png

What just happened?

The code built a 4-node graph with conditional routing from node_a, then compiled it. The <code>draw_mermaid_png()</code> call introspected the graph topology, generated Mermaid flowchart syntax representing START → node_a → (conditional) → node_b → node_c → END, rendered it to PNG via the Mermaid renderer, and saved the file as <code>graph.png</code> in the current working directory.

Common gotcha

Developers often assume draw_mermaid_png() works on the StateGraph object itself. It doesn't: you must call it on graph.compile(), the compiled instance. Calling it on the uncompleted graph will raise AttributeError. Also, conditional edges only show their branch labels in the diagram if the router function returns exactly those keys: typos in return values create confusing diagrams.

Error recovery

FileNotFoundError
The output directory doesn't exist. Create it first with <code>os.makedirs('output_dir', exist_ok=True)</code>, or pass an absolute path: <code>compiled.draw_mermaid_png(output_file_path='/tmp/graph.png')</code>
AttributeError: 'StateGraph' object has no attribute 'draw_mermaid_png'
You called <code>draw_mermaid_png()</code> on the StateGraph before compiling. Change <code>graph.draw_mermaid_png(...)</code> to <code>graph.compile().draw_mermaid_png(...)</code>
ModuleNotFoundError: No module named 'PIL'
Mermaid rendering requires Pillow. Install with <code>pip install pillow</code>. Some environments also need <code>pip install cairosvg</code> for SVG rendering.

Experienced dev note

Save the PNG in your Git repo alongside your graph definition code, then regenerate it in CI/CD on every commit. This auto-documents your graph changes in pull requests: reviewers see exactly what control flow changed without reading the Python. Add a pre-commit hook: compiled.draw_mermaid_png(output_file_path='docs/graph.png') as part of your test suite, so a forgotten graph update fails the build.

Check your understanding

You have a conditional edge from node_x that can route to either 'success_node' or 'retry_node' based on a router function. When you export the PNG, you see the edge labels show 'success_node' and 'retry_node' on the diagram. Your router function's return statement is: return 'failed' if error else 'ok'. What will the PNG actually show as edge labels, and why?

Show answer hint

A correct answer recognizes that the PNG will show the edge dictionary keys (the conditional_edges target dict), not the router's return values: so you'll see whatever keys you passed to <code>add_conditional_edges()</code>. If the router returns 'failed' but your edge dict has {'error': 'retry_node'}, there's a mismatch and the diagram won't reflect the actual routing.

VERSION In langgraph < 0.2.0, this method was called draw_mermaid() and returned a string. In 0.2.0+, it's draw_mermaid_png() and writes directly to disk. If you need the Mermaid string without writing a file, call compiled.get_graph().draw_mermaid() instead.
NEXT

Next, learn how to programmatically inspect graph state at runtime using <code>graph.get_state()</code> during execution: seeing what data flows between nodes when your graph actually runs.

Community Notes

No notes yetBe the first to share a version-specific fix or tip.