This is an introductory tutorial to the world of LangGraph.js.
In this tutorial, we will explore the foundational building blocks of graph structures used to define AI Agents and their behavior.
While the first part of this example may seem simple, a good understanding of the topics discussed will help as we progress.
Keep an eye on the next part of this series, where we will add LLMs and AI Agents into the mix to build more practical examples.
In this tutorial we will go thought the folowing:
- Installing LangGraph.js
- Nodes, Edges, and Graphs in LangGraph.js
- Conditional Edges
- Cycles in LangGraph.js
- Conclusion and Source Code
Installing LangGraph.js
Before we can create our first graphs, we need to ensure LangGraph.js is installed. The steps are very similar to what I've covered in my tutorial on how to set up LangChain with Node.js.
For now, you wonβt need an OpenAI API key, so you can skip that part.
The only extra step is installing the LangGraph.js library. We will also need @langchain/core installed.
npm install @langchain/langgraph @langchain/core
Don't worry, there is also a link to the full code at the end of this article.
Nodes, Edges, and Graphs in LangGraph.js
Graphs are an ideal data structure to describe a logical schema that encapsulates the behavior we expect from an AI Agent.
Letβs define a simple structure like this:
START --> nodeA --> nodeB --> END
I know this example is simple, but donβt worry, things will get more complex as we proceed.
Each node will be a function that gets executed when we reach that node. The nodes will be linked in a coherent structure using edges.
Here's how it looks in code:
import { END, START, MessageGraph } from "@langchain/langgraph"
import * as fs from "fs"
const funcA = input => {
input[0].content += " A output";
return input
}
const funcB = input => {
input[0].content += " B output";
return input
}
// build the graph
const graph = new MessageGraph()
// nodes
.addNode("nodeA", funcA)
.addNode("nodeB", funcB)
// edges
.addEdge(START, "nodeA")
.addEdge("nodeA", "nodeB")
.addEdge("nodeB", END)
const runnable = graph.compile()
const result = await runnable.invoke('Initial input')
console.log(result)
Both START and END are simple string constants indicating the entry and exit points of the graph.
The flow is straightforward: we move from nodeA to nodeB, with each node adding something to the initial input.
The result of running the code:
[
HumanMessage {
"id": "675cb46c-2637-4ea5-ad35-1cde12615e49",
"content": "Initial input A output B output",
"additional_kwargs": {},
"response_metadata": {}
}
]
Since LangGraph.js uses LangChain's runnables, we can easily chain multiple calls, much like in the old days of jQuery:
const graph = new MessageGraph()
.addNode(...)
.addNode(...)
.addEdge(...)
.addEdge(...)
In a future article, we will see how easy it is to render the graph structure as an image. For now, note that the GitHub repository includes PNGs showing the flow of the graph, which are helpful for debugging.
Conditional Edges in LangGraph.js
In addition to simple direct edges, LangGraph.js allows for conditional edges.
Using conditional edges, the flow of the graph can be routed through different parts of the graph based on a given condition.
Here's some code that builds a graph with two conditional edges:
import { END, START, MessageGraph } from '@langchain/langgraph'
const funRed = input => {
input[0].content += 'π΄ π΄ π΄'
return input
}
const funBlue = input => {
input[0].content += 'π΅ π΅ π΅'
return input
}
const funDecision = input =>
input[0].content.includes('red') ?
'actionRed' :
'actionBlue'
const graph = new MessageGraph()
// setup nodes
graph.addNode('decision', funDecision)
.addNode('actionRed', funRed)
.addNode('actionBlue', funBlue)
// setup edges
graph.addEdge(START, "decision")
.addConditionalEdges(
"decision",
funDecision,
["actionRed", "actionBlue"]
)
.addEdge('actionRed', END)
.addEdge('actionBlue', END)
const runnable = graph.compile()
const result = await runnable.invoke('Input - use action blue - Result:')
console.log(result)
Based on the result of the decision, if the initial input contains the word blue, the graph will execute funBlue. Otherwise, it will execute funRed, adding the respective markers to the output.
This is the final output:
HumanMessage {
"id": "c6e0e2fe-bb8b-494b-a019-bd54ad7cbbf4",
"content": "Input - use action blue - Result : π΅ π΅ π΅",
"additional_kwargs": {},
"response_metadata": {}
}
Cycles
So far, most of what we've done in this tutorial could also be achieved with LCEL - LangChain Expression Language.
However, creating cycles (or loops) is not possible within LCEL.
We can think of AI Agents as LLMs running in a do-while loop until they achieve a specific objective. We provide an AI Agent with an objective and a set of tools, and it loops through different strategies to accomplish the objective.
Therefore, cycles are a crucial component in describing AI Agent behavior with LangGraph.js.
Let's simulate an AI agent with the following:
- An objective: roll a 6 with a dice
- A dice tool that can roll any number between 1 and 6
The idea is to keep rolling the dice until the agent reaches its objective.

This is how the JavaScript code for this scenario will look like:
import { END, START, MessageGraph } from '@langchain/langgraph'
import { HumanMessage } from '@langchain/core/messages'
const funAgent = input => input
const funUseDiceTool = input => {
const dice = 1 + Math.floor(Math.random() * 6)
const content = (dice !== 6) ?
'π² rolled: ' + dice :
'objective_achieved'
input.push(new HumanMessage(content))
return input
}
const shouldContinue = input => {
return input.pop().content.includes('objective_achieved') ?
'end' :
'useDiceTool'
}
const graph = new MessageGraph()
// setup nodes
graph.addNode('agent', funAgent)
.addNode('useDiceTool', funUseDiceTool)
// setup edges
graph.addEdge(START, 'agent')
.addEdge('useDiceTool', 'agent')
.addConditionalEdges(
'agent',
shouldContinue,
{'useDiceTool': 'useDiceTool', 'end': END}
)
const runnable = graph.compile()
const result = await runnable.invoke('Start game')
console.log(result)
As you can see there isn't a new special type of edge we add. We are budding a cycle by using a simple conditional edge.
Hereβs an example of the output:
[
HumanMessage {
"id": "3ad9e1fa-9c93-47aa-aa7d-045286179765",
"content": "Start game",
"additional_kwargs": {},
"response_metadata": {}
},
HumanMessage {
"id": "c08ea29e-39b4-4cd1-9216-10357cd569b7",
"content": "π² rolled: 3",
"additional_kwargs": {},
"response_metadata": {}
},
HumanMessage {
"id": "053a44d1-1155-45ba-abfb-67b952086277",
"content": "objective_achieved",
"additional_kwargs": {},
"response_metadata": {}
}
]
Of course keep in mind that each random run will look different. The overall idea is to keep the agent running until it reaches its objective.
Conclusion and source code
And there you have it! These are the fundamental building blocks of defining graphs with LangGraph.js. You can check out the full code of this tutorial on my GitHub.
In the next part of this tutorial, weβll look at how to use LLMs with LangGraph.js to create a real AI Agent.
Be kind, be smart, and keep coding!
π Build a full trivia game app with LangChain
Learn by doing with this FREE ebook! This 35-page guide walks you through every step of building your first fully functional AI-powered app using JavaScript and LangChain.js
π Build a full trivia game app with LangChain
Learn by doing with this FREE ebook! This 35-page guide walks you through every step of building your first fully functional AI-powered app using JavaScript and LangChain.js