Database & State Storage Patterns
LangGraph separates state into two layers: checkpointers for within-thread history and the Store for cross-thread memory. Choosing the right backend for each layer — and knowing what breaks when you get it wrong — is what this article covers.
Quick Reference
- →Checkpointers handle short-term state within a thread; the Store handles long-term memory across threads
- →AsyncPostgresSaver: durable, ACID-compliant, full checkpoint history — the safe production default
- →AsyncRedisSaver: lower latency than Postgres; requires AOF persistence or you lose checkpoints on restart
- →AsyncShallowRedisSaver: stores only the latest checkpoint, cutting Redis memory by 60–80% for simple agents
- →PostgresStore / RedisStore: LangGraph's built-in Store API for cross-thread memory with optional semantic search
- →Checkpoint tables grow at ~3 rows per invocation per node; plan a retention policy before first production deploy
- →Call checkpointer.setup() and store.setup() once at startup — both are idempotent
Two-Tier Memory: Checkpoints vs Store
LangGraph's persistence model has two distinct layers that engineers regularly conflate. Getting them confused leads to building redundant infrastructure or using the wrong tool for a job. The checkpointer handles within-thread state — what happened in this conversation. The Store handles across-thread state — what should persist across all conversations for a user.
Checkpointer = thread-scoped auto-save · Store = cross-thread shared memory
| Checkpointer | Store | |
|---|---|---|
| Scope | Single thread (one conversation) | Cross-thread (all conversations) |
| Written by | LangGraph automatically after each node | Your nodes explicitly via store.put() |
| Read by | LangGraph automatically on resume | Your nodes explicitly via store.get() / store.search() |
| Typical content | Full graph state: messages, tool results, intermediate values | User facts, preferences, summaries, learned context |
| Grows with | Every node execution | Explicit writes from your code |
| Production backends | AsyncPostgresSaver, AsyncRedisSaver, AsyncMongoDBSaver | PostgresStore, RedisStore |
| Dev backend | InMemorySaver (built-in) | InMemoryStore (built-in) |
Factory function is the only swap point — the chain never sees the backend
If your agent needs to remember a user's preferred language or summarized facts across sessions, that's the Store API — not a custom Redis hash. Use InMemoryStore for dev and PostgresStore for production. One import line change, same interface.