Skip to content

Build1 publisher3 min readPublished

Seven conditions that justify rewriting an n8n agent in LangGraph

A dev.to migration guide rests the case for LangGraph on durable state, pause/resume approvals and testable branches, and it tells you to leave the CRM, the property database and the external APIs exactly where they are.

The Engineer · Build desk

Illustration accompanying Seven conditions that justify rewriting an n8n agent in LangGraph

What happened

  • A dev.to migration guide sets out seven scenarios that make moving agent logic out of an n8n prototype worthwhile, among them untraceable agent decisions, complicated retry logic and human approval needing pause/resume.
  • The guide confines the rewrite to the orchestration layer and says the CRM, the property database and the external APIs do not necessarily need to move.
  • Its worked LangGraph version declares a TypedDict called AgentState holding user_query, requirements, candidates, matches, selected_property and error as the contract every node reads and writes.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • decision The trigger list gives a team a pass/fail test to run before anyone opens an editor: name the condition you are hitting, or the rewrite has no requirement behind it and you cannot defend it at review.
  • cost Following the advice leaves you operating both systems at once, and somebody has to own the handoff between the integrations that stayed and the Python graph that now holds the decisions.
  • capability Once intermediate values live in one declared contract, an approval that halts for a day becomes implementable, because there is a single object to persist and reload rather than data in flight between nodes.
  • constraint The contract also tightens later changes: adding a field means editing the shared type that every node depends on. That is a different kind of work from appending a node to a canvas.

The change that costs the most rewriting is the state declaration. The guide's `AgentState` is a `TypedDict` with six keys: `user_query`, `requirements`, `candidates`, `matches`, `selected_property` and `error` [13]. Two of the six admit `None` [14]. An `error` typed `str | None` means a failed lookup is a value sitting in shared state, readable by any later node. No exception escapes the executor. In n8n, the guide notes, execution data flows from one node to the next; in LangGraph the shared state is declared up front [15]. Its rule for what belongs there: information required by more than one stage of the agent [16].

The graph itself is small. One `StateGraph(AgentState)`, three `add_node` calls for `normalize_request`, `search_properties` and `rank_properties`, four `add_edge` calls wiring `START` through to `END`, then `builder.compile()` [17][18]. The step diagram for the same conversion also names a `route_result` node; the code sample declares only those three [22]. The diagram is ahead of the code, which is the usual order of things. It matters here, because the routing node is where retry and approval logic ends up.

The trigger is requirements, and the guide says so directly: "Replacing n8n just because LangGraph is newer is not quite the point." [3] What should move, it argues, are the parts needing stateful agent orchestration, explicit control flow, persistence and long-running execution [4]. The workflow it treats as the moment to evaluate has more than 20 nodes, multiple IF branches, an AI Agent node, multiple tool calls, retries, human approval, a CRM update, a follow-up and a scheduled continuation [11]. The guide's term for that is an "agentic state machine" [12].

Before any code, its first instruction is inspection: walk every node and determine what responsibility it actually performs [5]. That classification exists to prevent what the guide calls one of the biggest migration mistakes, rewriting the entire system when only the agent orchestration needs to change [6]. The CRM, the property database and the external APIs do not necessarily move at all [7].

The guide publishes no measurements of either version, and the published text breaks off mid-sentence just after the compile step, before showing how pause/resume is wired [20][21]. So this is a design argument. It transfers only if you can name which of the seven conditions you are hitting, on a workflow you can point at.

The worked example is a real estate assistant handling a request like "Looking for a 3-bedroom apartment in Dubai Marina under AED 2 million" [8][9]: extract, search, filter, rank, return [9]. In my view, only one condition on the list justifies a rewrite on its own, and that is the approval pause. My workloads stop for human sign-off. An execution that cannot resume with the same values re-runs every model call it already paid for, and the guide lists persistence and long-running execution beside it for that reason [1].

What to watch

  • Whether the remainder of the guide publishes an actual checkpointer configuration for the pause/resume case it uses as a justification.
  • Any measured comparison of the two versions on latency, model spend or failure rate.
  • Whether n8n adds durable state and approval primitives that remove several of the seven conditions from the list.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories