# LangGraph Workflows: Sequential & Parallel

> Source: <https://pub.towardsai.net/langgraph-workflows-sequential-parallel-0924548089f5?source=rss----98111c9905da---4>
> Published: 2026-09-20 12:01:03+00:00

A workflow in LangGraph is a series of steps or tasks arranged to accomplish a specific goal. LangGraph supports a few fundamental patterns for arranging these steps, and in this post I’ll focus on the two simplest ones: sequential and parallel. Most real applications end up combining multiple patterns into one graph, but it helps to understand each in isolation first.

I’ll use the essay reviewer here, with a slightly expanded state:

``` python
from typing import TypedDictclass EssayState(TypedDict):    essay: str    clarity: str    depth: str    language_and_grammer: str    overall_score: int    overall_feedback: str
```

Instead of reviewing the essay in one giant LLM call, I’m splitting the evaluation into separate nodes, one for each parameter (clarity, depth, language and grammar), plus a final node that combines them into an overall score and summary. This is what actually lets us demonstrate the difference between sequential and parallel execution.

Each check gets its own Pydantic schema, so every node only asks the LLM for one thing at a time.

``` python
from pydantic import BaseModel, Fieldclass ClarityCheck(BaseModel):    clarity: str = Field(description="Feedback on the clarity of the topic in the essay")class DepthCheck(BaseModel):    depth: str = Field(description="Feedback on the depth of the topic in the essay")class LanguageCheck(BaseModel):    language_and_grammer: str = Field(description="Feedback on the language and grammar presented in the essay")class OverallEvaluation(BaseModel):    overall_score: int = Field(description="Overall score out of 10 based on all three checks", ge=0, le=10)    overall_feedback: str = Field(description="Overall feedback summarizing the essay")
```

*And the corresponding node functions:*

``` python
def check_clarity(state: EssayState):    prompt = f"""You are an essay grading assistant. Evaluate only the clarity of the following essay, how well the ideas are expressed and easy to follow.Essay:    {state["essay"]}    """    clarity_llm = llm_model.with_structured_output(ClarityCheck)    response = clarity_llm.invoke(prompt)    return {"clarity": response.clarity}def check_depth(state: EssayState):    prompt = f"""You are an essay grading assistant. Evaluate only the depth of the following essay, how well the topic is explored and substantiated.    Essay:    {state["essay"]}    """    depth_llm = llm_model.with_structured_output(DepthCheck)    response = depth_llm.invoke(prompt)    return {"depth": response.depth}def check_language(state: EssayState):    prompt = f"""You are an essay grading assistant. Evaluate only the language and grammar of the following essay.    Essay:    {state["essay"]}    """    language_llm = llm_model.with_structured_output(LanguageCheck)    response = language_llm.invoke(prompt)    return {"language_and_grammer": response.language_and_grammer}def generate_overall_feedback(state: EssayState):    prompt = f"""You are an essay grading assistant. Based on the following three pieces of feedback, give an overall score out of 10 and a concise overall summary.    Clarity feedback: {state["clarity"]}    Depth feedback: {state["depth"]}    Language and grammar feedback: {state["language_and_grammer"]}    """    overall_llm = llm_model.with_structured_output(OverallEvaluation)    response = overall_llm.invoke(prompt)    return {        "overall_score": response.overall_score,        "overall_feedback": response.overall_feedback    }## With these four nodes in place, ## we can now wire them into a graph two different ways.
```

This is the simplest type of workflow you can build with LangGraph. It contains steps arranged in a single sequence, executed one after another. If node A finishes, node B runs next, every time, no branching or looping involved. For the essay reviewer, running the checks sequentially means clarity finishes before depth starts, and depth finishes before language and grammar start.

```
seq_workflow = StateGraph(EssayState)seq_workflow.add_node("check_clarity", check_clarity)seq_workflow.add_node("check_depth", check_depth)seq_workflow.add_node("check_language", check_language)seq_workflow.add_node("generate_overall_feedback", generate_overall_feedback)seq_workflow.add_edge(START, "check_clarity")seq_workflow.add_edge("check_clarity", "check_depth")seq_workflow.add_edge("check_depth", "check_language")seq_workflow.add_edge("check_language", "generate_overall_feedback")seq_workflow.add_edge("generate_overall_feedback", END)seq_workflow = seq_workflow.compile()
```

Every edge here is a plain add_edge, a fixed path from one node to the next. This is functionally identical to what a LangChain chain would already handle well. The three checks don’t depend on each other’s output, but running them one after another still works, it’s just slower than it needs to be.

A parallel workflow lets you run multiple independent tasks at the same time, instead of one after another. This matters whenever steps don’t depend on each other’s output, running them sequentially in that case is just wasted time.

In our essay reviewer, check_clarity, check_depth, and check_language are a perfect fit for this. None of them need the output of the others, they all just need the raw essay text. So instead of chaining them, we fan them out from START and let LangGraph run them concurrently, converging on generate_overall_feedback once all three are done.

```
par_workflow = StateGraph(EssayState)par_workflow.add_node("check_clarity", check_clarity)par_workflow.add_node("check_depth", check_depth)par_workflow.add_node("check_language", check_language)par_workflow.add_node("generate_overall_feedback", generate_overall_feedback)par_workflow.add_edge(START, "check_clarity")par_workflow.add_edge(START, "check_depth")par_workflow.add_edge(START, "check_language")par_workflow.add_edge("check_clarity", "generate_overall_feedback")par_workflow.add_edge("check_depth", "generate_overall_feedback")par_workflow.add_edge("check_language", "generate_overall_feedback")par_workflow.add_edge("generate_overall_feedback", END)par_workflow = par_workflow.compile()
```

All three checks branch off START directly, and all three feed into generate_overall_feedback. LangGraph waits for all three to finish before running that final node, this is often called a fan out, fan in pattern. Same nodes as the sequential version, same final result, but the three independent checks now run at the same time instead of waiting on each other.

*The difference here isn’t in what the graph produces, both versions land on the same overall_score and overall_feedback. The difference is in how the work is scheduled. Sequential is simpler to reason about and is the right choice when steps genuinely depend on each other. Parallel is faster whenever steps are independent, which is exactly the case with our three essay checks.*

Next up, I’ll cover conditional and iterative workflows, using a different example better suited to branching and looping logic.

[LangGraph Workflows: Sequential & Parallel](https://pub.towardsai.net/langgraph-workflows-sequential-parallel-0924548089f5) was originally published in [Towards AI](https://pub.towardsai.net) on Medium, where people are continuing the conversation by highlighting and responding to this story.
