Checkpointers and threads
Ark’s continuity is hand-rolled: session.json, a writeback hook, an incident log. LangGraph ships this as first-class primitives. This module puts a Postgres checkpointer under the module 3 dice graph, kills the process mid-run, resumes, and walks the checkpoint lineage.
A checkpointer persists graph state after every step. Compile the graph with one and every node transition writes a snapshot. If the process dies, the thread resumes from the last snapshot instead of the start.
import { PostgresSaver } from "@langchain/langgraph-checkpoint-postgres";
const checkpointer = PostgresSaver.fromConnString("postgresql://…");
await checkpointer.setup(); // creates the tables, run once
const graph = builder.compile({ checkpointer });For dev, MemorySaver from @langchain/langgraph is the in-memory equivalent, gone when the process exits. The Postgres and SQLite savers live in their own packages: @langchain/langgraph-checkpoint-postgres and -sqlite.
A thread is a conversation’s identity. You pass a thread_id in config; all checkpoints for that thread are its history. Same thread_id resumes; a new thread_id starts fresh.
const config = { configurable: { thread_id: "impulse-2026-07-04" } };
await graph.invoke(inputs, config);
// process dies here…
// …new process, same config:
await graph.invoke(null, config); // resumes from last checkpointTry it yourself
What thread_id identifies
One value decides this, and it is passed at call time rather than configured on the graph.
What determines resume vs fresh start when you call graph.invoke?
Reveal answer
The thread_id passed in config.configurable. Reusing the same thread_id with a checkpointer under the graph resumes from that thread's last checkpoint; a new thread_id starts a fresh run with no prior history.
Why null inputs on resume
graph.invoke(null, config) resumes a thread using null as the inputs. Where does the graph actually get its state from?
Show answer
Correct answer: B — The checkpointer supplies state from the last checkpoint for that thread_id, so no inputs needed
Because the checkpointer already has the thread's last saved state, invoking with null inputs tells the graph "don't start over, continue from what's persisted." The state comes from the checkpoint, not from the invoke call's arguments.