Skip to content
Craft Solution Tech

LangGraph for JS devs: graphs and nodes without the headache

Graph, Node, Edge, State: four scary words that fit inside a cooking recipe. Explained through a rap battle between Molière and Robespierre.

5 min read

Infographic, in French: the three pillars of a LangGraph graph — the Node as a single-task function, the State as shared memory, the Edge as the route guide — plus the anatomy of the rap battle workflow with its conditional edge.
Node, State, Edge, and the conditional edge that keeps the battle looping. (Original graphic, in French.)

When I started learning LangGraph, I got stuck on the basic concepts.

Graph? Node? Edge? State?

It looked complicated. It is actually simple once you have the right analogy.


A graph is just a route

Picture a cooking recipe.

You have steps (chop the vegetables, fry them, season…) and an order (you chop before you fry).

A graph in LangGraph is the same:

  • The steps = the Nodes
  • The order = the Edges (the arrows between the steps)

That is all it is…


A node is a function that does ONE thing

A node receives a state, does something, and returns a new state.

const chopTheVegetables = (state: RecipeState) => {
  return {
    vegetables: ["carrots", "onions"],
    step: "vegetables chopped"
  };
};

Each node has a single responsibility. No more.


The state is the memory of the route

The state holds all the information that travels between the nodes.

In LangGraph, you define it with Annotations:

const RecipeState = Annotation.Root({
  vegetables: Annotation<string[]>,
  seasoning: Annotation<string>,
  step: Annotation<string>,
});

Every node can read the state and change it. The state evolves along the route.


A concrete example: an AI rap battle 🎤

To really get it with something fun: a rap battle between Molière and Robespierre, judged by an LLM.

The battle state

const BattleState = Annotation.Root({
  theme: Annotation<string>,
  moliereVerse: Annotation<string>,
  robespierreVerse: Annotation<string>,
  moliereScore: Annotation<number>,
  robespierreScore: Annotation<number>,
  round: Annotation<number>,
  winner: Annotation<string>,
});

The nodes

  1. pickTheme → generates a random battle theme
  2. moliereRaps → Molière drops his verse (alexandrines, ABAB rhymes)
  3. robespierreRaps → Robespierre answers (revolutionary rhetoric, AABB rhymes)
  4. judge → a third LLM scores both verses
  5. announceWinner → declares the winner

The edges (the route)

pickTheme → moliereRaps → robespierreRaps → judge → ...

But there is a twist: after judge, we either want another round or the end.

That is where conditional edges come in.


Conditional edges: dynamic routing

Sometimes the route is not linear. It depends on a condition.

graph.addConditionalEdges("judge", (state) => {
  if (state.round < 3) {
    return "moliereRaps"; // the battle continues
  }
  return "announceWinner"; // 3 rounds = the end
});

The flow changes according to the state. That is the power of LangGraph.


Visual recap

┌─────────────┐
│  pickTheme  │
└──────┬──────┘
       ▼
┌─────────────┐
│ moliereRaps │◄──────────┐
└──────┬──────┘           │
       ▼                  │
┌─────────────────┐       │
│ robespierreRaps │       │
└──────┬──────────┘       │
       ▼                  │
┌─────────────┐   round < 3
│    judge    │───────────┘
└──────┬──────┘
       │ round >= 3
       ▼
┌────────────────┐
│ announceWinner │
└────────────────┘

What I took away

ConceptIn plain words
GraphA route with steps
NodeA function that does ONE thing
EdgeAn arrow between two steps
StateThe memory shared between the nodes
Conditional edgeAn arrow that depends on a condition

Why is it useful?

When you build AI agents, you often need to:

  • chain several LLM calls
  • make decisions based on the answers
  • keep state between the steps

LangGraph structures all of that cleanly. No spaghetti code.


Going further


Just getting started with LangGraph? Write to me about what is blocking you — I might turn it into an article.

Covered here

  • AI
  • LangGraph
  • TypeScript
  • JavaScript

Tell us what you are trying to build.

Message us on WhatsApp
Back to the blog