I built my first bot in Python. It used fixed graph code. It worked for static tasks.
But clients wanted a change. They wanted a web editor.
They wanted custom graphs. They wanted to save flows as JSON.
Fixed Python scripts could not do this. I had to build a graph compiler.
A graph compiler takes a JSON file. It reads nodes and edges.
It maps node names to Python code. It builds a fresh StateGraph on the fly.
Compiling graphs from JSON needs strict rules. You need a node map.
You need state checks. You need safe routing.
Here is what I learned from compiling graphs in production.
Before looking at code, let us see why dynamic builds matter.
Standard graph code defines nodes in Python files. Developers write functions for each node.
They add fixed edges between nodes. They compile the graph at launch time.
This setup works for static bots. But it fails when users need custom flows.
If a user swaps a search node for a database node, you must edit Python code. You must redeploy your server.
JSON is the standard format for web editors. Frontends output JSON graphs with node IDs and connections.
Compiling from JSON lets your backend build custom AI bots fast. Users edit workflows in a browser.
Your server parses the new JSON. It runs the graph right away.
Do not let JSON payloads send raw code. That creates big security risks.
Use a strict node map instead. Map string keys in JSON to pre-written Python functions.
"type": "llm_call"."llm_call" to a safe Python function.add_node("agent", map["llm_call"]).This map pattern keeps your backend safe from code injection attacks.
Every StateGraph needs a state schema. Fixed graphs use TypedDict or Pydantic models.
When compiling from JSON, your state keys change.
I build dynamic state schemas using Pydantic:
create_model().StateGraph(DynamicModel).This check ensures every node gets clean, typed state data.
LangGraph uses conditional edges to route graph steps. Fixed graphs use Python functions to check state.
JSON graphs cannot send raw Python code for routing.
Use a safe rule parser for edges:
"if state.score > 0.8 route to 'approve' else 'reject'".
Do not use eval() or exec() in your routing code.
Dynamic graphs need memory and state storage. You must save graph state after every step.
Pass a saver object when compiling your graph:
MemorySaver for short tests.PostgresSaver for real apps.workflow.compile(checkpointer=saver) at the end of your builder loop.Attaching savers enables human approval steps on dynamic graphs.
Users can draw cyclic loops in web editors. If a loop condition stays true, your graph runs forever.
Set hard step limits on runtime graphs:
recursion_limit=20 in your run setup.Step limits protect your server from high API costs.
In a web editor, a user might connect an image tool node to a text node. The output of Node A will not match Node B.
Check node links before compiling:
StateGraph().Checks stop broken graphs from failing mid-run.
Some users want to write custom code scripts inside node blocks.
Never run custom code on your main app server.
If you support custom code nodes:
Sandboxing keeps your core server safe from bad user code.
| Feature | Fixed Python Graph | Runtime JSON Build |
|---|---|---|
| Flow Source | Python source files | JSON payload from UI |
| Flexibility | Fixed at deploy time | Dynamic per request |
| Node Mapping | Direct Python code | Map lookup table |
| Security Risk | Very low | Needs strict sandboxing |
| Best Use | Fixed bot logic | Custom web editors |
Dynamic JSON builds give you total freedom for custom agent tools.
create_model() to make state schemas on the fly.eval() when checking edge rules in JSON.
Compiling a LangGraph StateGraph from JSON opens up great options. You can build web editors, no-code AI tools, and dynamic agent runners.
However, runtime builds need clear limits. You must secure your node handlers, check dynamic state schemas, and stop infinite loops.
If you build customizable AI tools today, combining LangGraph with JSON compilation is a top choice.
Use a dictionary lookup table. Store Python functions as values, and use JSON string keys to attach node handlers.
Yes. It is safe if you use a fixed node map and avoid running raw code with eval().
Define simple condition rules in JSON. Write a parser function that checks state keys against rule values safely.
Yes. Pass a PostgresSaver object to the .compile() method after building your dynamic graph from JSON.