LangGraph Tutorial (TypeScript): connecting to PostgreSQL for intermediate developers
This tutorial shows you how to wire a LangGraph TypeScript app to PostgreSQL so your graph can persist state across runs. You need this when you want resumable workflows, durable checkpoints, or shared conversation state that survives process restarts.
What You'll Need
- •Node.js 18+
- •A PostgreSQL instance running locally or in Docker
- •A database URL like
postgresql://postgres:postgres@localhost:5432/langgraph_demo - •An OpenAI API key if you want to use an LLM node
- •Packages:
- •
@langchain/langgraph - •
@langchain/openai - •
pg - •
dotenv - •
typescript - •
tsx
- •
Step-by-Step
- •Set up the project and install dependencies. This gives you the LangGraph runtime, a Postgres client, and a simple way to run TypeScript directly.
mkdir langgraph-postgres-demo
cd langgraph-postgres-demo
npm init -y
npm install @langchain/langgraph @langchain/openai pg dotenv
npm install -D typescript tsx @types/node @types/pg
- •Create your environment file and start PostgreSQL. LangGraph will use the database connection string through the checkpointer, so keep it in
.envand load it at runtime.
cat > .env << 'EOF'
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/langgraph_demo
OPENAI_API_KEY=your_openai_key_here
EOF
docker run --name langgraph-pg \
-e POSTGRES_USER=postgres \
-e POSTGRES_PASSWORD=postgres \
-e POSTGRES_DB=langgraph_demo \
-p 5432:5432 \
-d postgres:16
- •Create the graph with a Postgres-backed checkpointer. The important part is
PostgresSaver.fromConnString(...), which stores checkpoints in PostgreSQL instead of memory.
import "dotenv/config";
import { ChatOpenAI } from "@langchain/openai";
import { StateGraph, Annotation, START, END } from "@langchain/langgraph";
import { PostgresSaver } from "@langchain/langgraph/checkpoint-postgres";
const State = Annotation.Root({
messages: Annotation<any[]>({
reducer: (left, right) => left.concat(right),
default: () => [],
}),
});
const model = new ChatOpenAI({ model: "gpt-4o-mini" });
async function main() {
const checkpointer = await PostgresSaver.fromConnString(process.env.DATABASE_URL!);
- •Add a node and compile the graph with persistence enabled. The node reads the current messages from state, calls the model, and returns the next message into the same thread.
const app = new StateGraph(State)
.addNode("chat", async (state) => {
const response = await model.invoke(state.messages);
return { messages: [response] };
})
.addEdge(START, "chat")
.addEdge("chat", END)
.compile({ checkpointer });
const threadId = "customer-123";
const firstRun = await app.invoke(
{ messages: [{ role: "user", content: "Write one sentence about PostgreSQL checkpoints." }] },
{ configurable: { thread_id: threadId } }
);
console.log(firstRun.messages.at(-1)?.content);
- •Run it twice with the same thread ID to confirm state is persisted. On the second call, LangGraph loads the checkpoint from PostgreSQL before continuing execution.
const secondRun = await app.invoke(
{ messages: [{ role: "user", content: "Now explain why this matters for resumable workflows." }] },
{ configurable: { thread_id: threadId } }
);
console.log(secondRun.messages.map((m) => m.content).join("\n"));
}
main().catch(console.error);
Testing It
Run the script with npx tsx index.ts. If everything is wired correctly, you should see model output on both invocations using the same thread_id.
To verify persistence, inspect your database after the first run:
docker exec -it langgraph-pg psql -U postgres -d langgraph_demo
Then query the checkpoint tables created by LangGraph. You should see rows associated with your thread after execution.
If you stop and restart your Node process, then run the script again with the same thread_id, LangGraph should continue using stored state instead of starting from scratch.
Next Steps
- •Add branching logic with conditional edges so your graph can route based on state.
- •Store richer structured state, not just messages, for claims intake or underwriting workflows.
- •Replace the single-node graph with multi-step agent flows and test rollback/resume behavior against PostgreSQL.
Keep learning
- •The complete AI Agents Roadmap — my full 8-step breakdown
- •Free: The AI Agent Starter Kit — PDF checklist + starter code
- •Work with me — I build AI for banks and insurance companies
By Cyprian Aarons, AI Consultant at Topiax.
Want the complete 8-step roadmap?
Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.
Get the Starter Kit