Welcome to the final lesson of our foundational module on LangChain. Over the past few lessons, we've explored the three essential building blocks of a basic LLM application: crafting dynamic prompts with ChatPromptTemplate, interacting with models like ChatOpenAI, and formatting their output with StringOutputParser.
So far, we've been connecting these pieces manually. Today, we'll put it all together and learn how to formally combine these components into a single, elegant, and reusable unit: a chain. This is the core concept that gives LangChain its name and power. By the end of this lesson, you will be able to construct a complete, invokable chain that takes an input, processes it through a prompt and a model, and returns a clean, parsed output.
The Anatomy of a Chain
At its heart, a LangChain application is a series of processing steps chained together, where the output of one step becomes the input for the next. The diagram below illustrates this fundamental flow perfectly.

This "pipelining" of components is made possible by the LangChain Expression Language (LCEL). While we will dedicate the entire next module to exploring LCEL's full power, you've already been using its most fundamental operator: the .pipe() method.
The .pipe() method is what allows us to chain components together. Let's see how this works in practice.
From Components to a Runnable Sequence
The process of building a chain is intuitive. You start with your first component (the prompt) and pipe the subsequent components (the model and the parser) to it in order.
prompt.pipe(model).pipe(parser)
This simple line of code creates a new object that encapsulates the entire sequence. LangChain calls this a RunnableSequence. For now, you can think of it simply as "the chain." This chain object can be stored, reused, and invoked as a single unit, which makes your code much cleaner and more modular than manually calling each component.
The following video from freeCodeCamp provides an excellent introduction to this concept. Watch the first part where the presenter builds their very first chain by piping a prompt into a model.
Learn LangChain.js - Build LLM apps with JavaScript and OpenAI
Watch the section where the presenter creates the tweetChain. Pay close attention to how the .pipe() method is used to connect the prompt and the model.
Start at this segment to see how a prompt and a model are joined to form a chain. Notice that the resulting object is a RunnableSequence, which contains the "first" and "last" elements of our chain.
As you saw, combining the prompt and the model creates a two-step chain. The final step is to pipe in our output parser to handle the model's response. The article "Langchain output parsers in Javascript" by JS-Craft demonstrates this complete three-step process very clearly.
Langchain output parsers in Javascript
This article concisely shows how to add a StringOutputParser to a chain.
Focus on the section The StringOutputParser. Compare the code and output before and after the stringParser is piped to the chain. This reinforces the value of adding the parser.
This prompt.pipe(model).pipe(parser) pattern is the most common and fundamental structure in LangChain. You have now seen how to assemble the core components into a functional, end-to-end chain.
Hands-On: Building a Joke Generator Chain
Now it's time to put this into practice. We'll build a simple but complete chain that generates a joke on a given topic.
Open your langchain-project and replace the content of src/index.ts with the following starter code:
// src/index.ts
import dotenv from 'dotenv';
import { ChatOpenAI } from "@langchain/openai";
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { StringOutputParser } from "@langchain/core/output_parsers";
dotenv.config();
const model = new ChatOpenAI({
modelName: "gpt-4o-mini",
temperature: 0.7,
});
async function main() {
// 1. Define the prompt template
// It should take a single input variable: "topic"
const prompt = ChatPromptTemplate.fromTemplate(
"Tell me a short joke about {topic}."
);
// 2. Create an instance of the output parser
const parser = new StringOutputParser();
// 3. Create the chain by piping the components together
// The order should be: prompt -> model -> parser
const chain = prompt.pipe(model).pipe(parser);
console.log("Invoking chain...");
// 4. Invoke the chain with a topic
const response = await chain.invoke({ topic: "TypeScript" });
// The response should be a string
console.log(response);
console.log("Type of response:", typeof response);
}
main();
Your task is to complete the code based on the comments.
- Define a
ChatPromptTemplatethat takes a{topic}variable. - Instantiate the
StringOutputParser. - Create the
chainby piping theprompt,model, andparsertogether in the correct order. - The rest of the code will
invokeyour chain and log the response.
Once you've completed the code, run it with npm start. If everything is set up correctly, you should see a joke printed in your console, and the type check will confirm that the final output is a string, not an AIMessage object.
This exercise solidifies the core workflow of building and using simple chains in LangChain.
Conclusion
Congratulations on completing the first module! You have successfully journeyed from individual components to building your first fully-fledged LangChain chain. This is a significant milestone.
Key Takeaways:
- A chain is a sequence of components where the output of one is passed as the input to the next.
- The
.pipe()method, part of the LangChain Expression Language (LCEL), is the primary way to connect components. - The canonical structure for a simple chain is
prompt.pipe(model).pipe(parser). - This creates a single, reusable
Runnableobject that can be invoked with an input object, simplifying your application's logic.
You now have a solid grasp of the fundamentals. You can take a user's input, format it, get a response from an LLM, and parse that response into a usable format.
In our next lesson, we will begin Module 2: LangChain Expression Language (LCEL). We'll go beyond simple linear pipes and explore the powerful, declarative syntax that allows you to build much more complex and sophisticated chains with features like parallel execution and dynamic data routing.