thread_id. A store persists facts across thread IDs.
For concepts, see the Functional API overview. For Graph API memory recipes, see Memory.
Save state on a thread
Pass a checkpointer when you create the entrypoint. Identify each run withthread_id.
Call getPreviousState inside the entrypoint. On the first run it is undefined.
import { entrypoint, getPreviousState, MemorySaver } from "@langchain/langgraph";
const checkpointer = new MemorySaver();
const accumulate = entrypoint(
{ checkpointer, name: "accumulate" },
async (n: number) => {
const previous = getPreviousState<number>() ?? 0;
return previous + n;
}
);
const config = { configurable: { thread_id: "1" } };
console.log(await accumulate.invoke(1, config)); // 1
console.log(await accumulate.invoke(2, config)); // 3
console.log(await accumulate.invoke(3, config)); // 6
Return a different saved value
Useentrypoint.final when the caller should receive one value and the next run should read another. value is returned to the caller.
save is what the next getPreviousState read sees.
For example, return a status or summary, and save the full internal state.
import { entrypoint, getPreviousState, MemorySaver } from "@langchain/langgraph";
const checkpointer = new MemorySaver();
const accumulate = entrypoint(
{ checkpointer, name: "accumulate" },
async (n: number) => {
const previous = getPreviousState<number>() ?? 0;
const total = previous + n;
// Return the *previous* value to the caller but save the *new* total.
return entrypoint.final({ value: previous, save: total });
}
);
const config = { configurable: { thread_id: "my-thread" } };
console.log(await accumulate.invoke(1, config)); // 0
console.log(await accumulate.invoke(2, config)); // 1
console.log(await accumulate.invoke(3, config)); // 3
Inspect checkpoints
View or delete checkpoints on theaccumulate workflow from Return a different saved value. values is the saved checkpoint (save), not the value returned to the caller.
View thread state
console.log(await accumulate.getState({
configurable: {
thread_id: "my-thread",
// optionally provide an ID for a specific checkpoint,
// otherwise the latest checkpoint is shown
// checkpoint_id: "1f1c1826-2179-626c-8004-96dc43069e17"
},
}));
StateSnapshot {
values: 3,
next: [],
config: { configurable: { thread_id: 'my-thread', checkpoint_ns: '', checkpoint_id: '1f1c1826-2179-626c-8004-96dc43069e17' } },
metadata: { source: 'loop', step: 4, parents: {} },
createdAt: '2026-10-06T12:35:16.081724+00:00',
parentConfig: { configurable: { thread_id: 'my-thread', checkpoint_ns: '', checkpoint_id: '1f1c1826-2178-6682-8003-feda9f2ec8db' } },
tasks: [],
interrupts: []
}
View thread history
const history = [];
for await (const state of accumulate.getStateHistory({
configurable: {
thread_id: "my-thread",
},
})) {
history.push(state);
}
console.log(history[0]);
StateSnapshot {
values: 3,
next: [],
config: { configurable: { thread_id: 'my-thread', checkpoint_ns: '', checkpoint_id: '1f1c1826-2179-626c-8004-96dc43069e17' } },
metadata: { source: 'loop', step: 4, parents: {} },
createdAt: '2026-10-06T12:35:16.081724+00:00',
parentConfig: { configurable: { thread_id: 'my-thread', checkpoint_ns: '', checkpoint_id: '1f1c1826-2178-6682-8003-feda9f2ec8db' } },
tasks: [],
interrupts: []
}
// ... earlier snapshots, including values 1, 0, and null
Delete checkpoints for a thread
await checkpointer.deleteThread("my-thread");
console.log(await accumulate.getState(config));
// StateSnapshot { values: {}, next: [], config: { configurable: { thread_id: 'my-thread' } }, ... }
Build a chatbot with checkpoints
Keep the conversation on the thread. Return the model message to the caller, and save the full list for the next turn withentrypoint.final.
import { BaseMessage } from "@langchain/core/messages";
import { ChatAnthropic } from "@langchain/anthropic";
import {
addMessages,
entrypoint,
getPreviousState,
task,
MemorySaver,
} from "@langchain/langgraph";
let model = new ChatAnthropic({ model: "google-genai:gemini-3.6-flash" });
const callModel = task(
"callModel",
async (messages: BaseMessage[]): Promise<BaseMessage> => {
const response = await model.invoke(messages);
return response;
}
);
const checkpointer = new MemorySaver();
const workflow = entrypoint(
{ checkpointer, name: "workflow" },
async (inputs: BaseMessage[]): Promise<BaseMessage> => {
const previous = getPreviousState<BaseMessage[]>();
let messages = inputs;
if (previous) {
messages = addMessages(previous, inputs);
}
const response = await callModel(messages);
return entrypoint.final({
value: response,
save: addMessages(messages, response),
});
}
);
const config = { configurable: { thread_id: "1" } };
const inputMessage = { role: "user", content: "hi! I'm bob" };
console.log(await workflow.invoke([inputMessage], config));
// -> AIMessage with a greeting that uses the name Bob
const inputMessage2 = { role: "user", content: "what's my name?" };
console.log(await workflow.invoke([inputMessage2], config));
// -> AIMessage that answers "Bob"
import { BaseMessage } from "@langchain/core/messages";
import { ChatAnthropic } from "@langchain/anthropic";
import {
addMessages,
entrypoint,
getPreviousState,
task,
MemorySaver,
} from "@langchain/langgraph";
let model = new ChatAnthropic({ model: "openai:gpt-5.5" });
const callModel = task(
"callModel",
async (messages: BaseMessage[]): Promise<BaseMessage> => {
const response = await model.invoke(messages);
return response;
}
);
const checkpointer = new MemorySaver();
const workflow = entrypoint(
{ checkpointer, name: "workflow" },
async (inputs: BaseMessage[]): Promise<BaseMessage> => {
const previous = getPreviousState<BaseMessage[]>();
let messages = inputs;
if (previous) {
messages = addMessages(previous, inputs);
}
const response = await callModel(messages);
return entrypoint.final({
value: response,
save: addMessages(messages, response),
});
}
);
const config = { configurable: { thread_id: "1" } };
const inputMessage = { role: "user", content: "hi! I'm bob" };
console.log(await workflow.invoke([inputMessage], config));
// -> AIMessage with a greeting that uses the name Bob
const inputMessage2 = { role: "user", content: "what's my name?" };
console.log(await workflow.invoke([inputMessage2], config));
// -> AIMessage that answers "Bob"
import { BaseMessage } from "@langchain/core/messages";
import { ChatAnthropic } from "@langchain/anthropic";
import {
addMessages,
entrypoint,
getPreviousState,
task,
MemorySaver,
} from "@langchain/langgraph";
let model = new ChatAnthropic({ model: "anthropic:claude-sonnet-4-6" });
const callModel = task(
"callModel",
async (messages: BaseMessage[]): Promise<BaseMessage> => {
const response = await model.invoke(messages);
return response;
}
);
const checkpointer = new MemorySaver();
const workflow = entrypoint(
{ checkpointer, name: "workflow" },
async (inputs: BaseMessage[]): Promise<BaseMessage> => {
const previous = getPreviousState<BaseMessage[]>();
let messages = inputs;
if (previous) {
messages = addMessages(previous, inputs);
}
const response = await callModel(messages);
return entrypoint.final({
value: response,
save: addMessages(messages, response),
});
}
);
const config = { configurable: { thread_id: "1" } };
const inputMessage = { role: "user", content: "hi! I'm bob" };
console.log(await workflow.invoke([inputMessage], config));
// -> AIMessage with a greeting that uses the name Bob
const inputMessage2 = { role: "user", content: "what's my name?" };
console.log(await workflow.invoke([inputMessage2], config));
// -> AIMessage that answers "Bob"
import { BaseMessage } from "@langchain/core/messages";
import { ChatAnthropic } from "@langchain/anthropic";
import {
addMessages,
entrypoint,
getPreviousState,
task,
MemorySaver,
} from "@langchain/langgraph";
let model = new ChatAnthropic({ model: "openrouter:openrouter:z-ai/glm-5.2" });
const callModel = task(
"callModel",
async (messages: BaseMessage[]): Promise<BaseMessage> => {
const response = await model.invoke(messages);
return response;
}
);
const checkpointer = new MemorySaver();
const workflow = entrypoint(
{ checkpointer, name: "workflow" },
async (inputs: BaseMessage[]): Promise<BaseMessage> => {
const previous = getPreviousState<BaseMessage[]>();
let messages = inputs;
if (previous) {
messages = addMessages(previous, inputs);
}
const response = await callModel(messages);
return entrypoint.final({
value: response,
save: addMessages(messages, response),
});
}
);
const config = { configurable: { thread_id: "1" } };
const inputMessage = { role: "user", content: "hi! I'm bob" };
console.log(await workflow.invoke([inputMessage], config));
// -> AIMessage with a greeting that uses the name Bob
const inputMessage2 = { role: "user", content: "what's my name?" };
console.log(await workflow.invoke([inputMessage2], config));
// -> AIMessage that answers "Bob"
import { BaseMessage } from "@langchain/core/messages";
import { ChatAnthropic } from "@langchain/anthropic";
import {
addMessages,
entrypoint,
getPreviousState,
task,
MemorySaver,
} from "@langchain/langgraph";
let model = new ChatAnthropic({ model: "fireworks:accounts/fireworks/models/glm-5p2" });
const callModel = task(
"callModel",
async (messages: BaseMessage[]): Promise<BaseMessage> => {
const response = await model.invoke(messages);
return response;
}
);
const checkpointer = new MemorySaver();
const workflow = entrypoint(
{ checkpointer, name: "workflow" },
async (inputs: BaseMessage[]): Promise<BaseMessage> => {
const previous = getPreviousState<BaseMessage[]>();
let messages = inputs;
if (previous) {
messages = addMessages(previous, inputs);
}
const response = await callModel(messages);
return entrypoint.final({
value: response,
save: addMessages(messages, response),
});
}
);
const config = { configurable: { thread_id: "1" } };
const inputMessage = { role: "user", content: "hi! I'm bob" };
console.log(await workflow.invoke([inputMessage], config));
// -> AIMessage with a greeting that uses the name Bob
const inputMessage2 = { role: "user", content: "what's my name?" };
console.log(await workflow.invoke([inputMessage2], config));
// -> AIMessage that answers "Bob"
import { BaseMessage } from "@langchain/core/messages";
import { ChatAnthropic } from "@langchain/anthropic";
import {
addMessages,
entrypoint,
getPreviousState,
task,
MemorySaver,
} from "@langchain/langgraph";
let model = new ChatAnthropic({ model: "baseten:zai-org/GLM-5.2" });
const callModel = task(
"callModel",
async (messages: BaseMessage[]): Promise<BaseMessage> => {
const response = await model.invoke(messages);
return response;
}
);
const checkpointer = new MemorySaver();
const workflow = entrypoint(
{ checkpointer, name: "workflow" },
async (inputs: BaseMessage[]): Promise<BaseMessage> => {
const previous = getPreviousState<BaseMessage[]>();
let messages = inputs;
if (previous) {
messages = addMessages(previous, inputs);
}
const response = await callModel(messages);
return entrypoint.final({
value: response,
save: addMessages(messages, response),
});
}
);
const config = { configurable: { thread_id: "1" } };
const inputMessage = { role: "user", content: "hi! I'm bob" };
console.log(await workflow.invoke([inputMessage], config));
// -> AIMessage with a greeting that uses the name Bob
const inputMessage2 = { role: "user", content: "what's my name?" };
console.log(await workflow.invoke([inputMessage2], config));
// -> AIMessage that answers "Bob"
import { BaseMessage } from "@langchain/core/messages";
import { ChatAnthropic } from "@langchain/anthropic";
import {
addMessages,
entrypoint,
getPreviousState,
task,
MemorySaver,
} from "@langchain/langgraph";
let model = new ChatAnthropic({ model: "ollama:north-mini-code-1.0" });
const callModel = task(
"callModel",
async (messages: BaseMessage[]): Promise<BaseMessage> => {
const response = await model.invoke(messages);
return response;
}
);
const checkpointer = new MemorySaver();
const workflow = entrypoint(
{ checkpointer, name: "workflow" },
async (inputs: BaseMessage[]): Promise<BaseMessage> => {
const previous = getPreviousState<BaseMessage[]>();
let messages = inputs;
if (previous) {
messages = addMessages(previous, inputs);
}
const response = await callModel(messages);
return entrypoint.final({
value: response,
save: addMessages(messages, response),
});
}
);
const config = { configurable: { thread_id: "1" } };
const inputMessage = { role: "user", content: "hi! I'm bob" };
console.log(await workflow.invoke([inputMessage], config));
// -> AIMessage with a greeting that uses the name Bob
const inputMessage2 = { role: "user", content: "what's my name?" };
console.log(await workflow.invoke([inputMessage2], config));
// -> AIMessage that answers "Bob"
Save facts across threads
Long-term memory lives in a store, not in the checkpointer. Save a fact on onethread_id and read it on another.
Pass an InMemoryStore when you create the entrypoint. Read and write it with config.store.
import {
MemorySaver,
InMemoryStore,
entrypoint,
} from "@langchain/langgraph";
import type { LangGraphRunnableConfig } from "@langchain/langgraph";
const checkpointer = new MemorySaver();
const store = new InMemoryStore();
const remember = entrypoint(
{ checkpointer, store, name: "remember" },
async (
inputs: { user_id: string; fact?: string },
config: LangGraphRunnableConfig
) => {
const namespace = [inputs.user_id, "memories"];
if (inputs.fact) {
await config.store!.put(namespace, "profile", { fact: inputs.fact });
}
const items = (await config.store!.search(namespace)) ?? [];
return items.map((item) => item.value);
}
);
const configA = { configurable: { thread_id: "thread-a" } };
const configB = { configurable: { thread_id: "thread-b" } };
await remember.invoke(
{ user_id: "user-1", fact: "Prefers dark mode" },
configA
);
console.log(await remember.invoke({ user_id: "user-1" }, configB));
// -> [{ fact: 'Prefers dark mode' }]
See also
- Functional API overview
- Build checklist for the Functional API
- Memory
- Persistence
- Stores
- Add human-in-the-loop with the Functional API
Connect these docs to your agent of choice via MCP for real-time answers.

