Production-ready PostgreSQL memory for LangGraph agents. Pool setup, checkpointer lifecycle, and common ops in one class.
Project description
LangGraph Postgres Memory
Production-ready PostgreSQL short-term memory for LangGraph agents. Pool setup, checkpointer lifecycle, and common operations in one class.
Note: This is a wrapper around langgraph-checkpoint-postgres — it does not reimplement checkpointing. It handles the boilerplate you'd otherwise copy-paste into every agent.
Features
- One-line setup — connection pool, checkpointer, and lifecycle managed via async context manager
- Production pool defaults — TCP keepalives, configurable idle/lifetime/timeout, schema isolation
- Retry with backoff — transient Postgres errors retried automatically via tenacity
- Thread cleanup — single CTE deletes across all 3 checkpoint tables in one round-trip
- Bulk cleanup — delete threads older than N days using UUID v6 timestamp comparison
- Health primitives —
ping()andpool_stats()for application health endpoints - Pydantic config — validated settings, pass however you load them (YAML, env vars, hardcoded)
Installation
# pip
pip install langgraph-postgres-memory
# uv
uv add langgraph-postgres-memory
Requirements
- Python >= 3.11
- PostgreSQL (tested with 16)
Usage
from langchain_core.messages import HumanMessage
from langgraph.graph import END, START, MessagesState, StateGraph
from langgraph_postgres_memory import PostgresMemoryConfig, PostgresShortTerm
# Define your graph
builder = StateGraph(MessagesState)
builder.add_node("echo", lambda state: {"messages": state["messages"]})
builder.add_edge(START, "echo")
builder.add_edge("echo", END)
# Configure memory
config = PostgresMemoryConfig(
user="myuser",
password="mypass",
host="localhost",
database="mydb",
schema_name="agent_schema", # default: "public"
)
async with PostgresShortTerm(config) as memory:
# Compile your graph with the checkpointer
graph = builder.compile(checkpointer=memory.checkpointer)
# Invoke as usual
result = await graph.ainvoke(
{"messages": [HumanMessage(content="hello")]},
{"configurable": {"thread_id": "thread-123"}},
)
# Read messages back
messages = await memory.get_messages("thread-123")
# Delete a thread
await memory.delete_thread("thread-123")
# Bulk cleanup
await memory.delete_threads_older_than(days=30)
# Health check
alive = await memory.ping()
stats = memory.pool_stats()
Without this library
# ~40 lines you copy-paste into every agent
conn_str = f"postgresql://{user}:{quote_plus(password)}@{host}:{port}/{db}"
conn_str += "?keepalives=1&keepalives_idle=30&..."
pool = AsyncConnectionPool(
conninfo=conn_str, min_size=2, max_size=10,
kwargs={"autocommit": True, "row_factory": dict_row},
configure=..., check=...,
)
await pool.open()
checkpointer = AsyncPostgresSaver(pool)
await checkpointer.setup()
# ... try/finally to close pool
# ... raw SQL to delete threads across 3 tables
# ... dig into checkpoint JSONB to extract messages
Configuration
All pool and retry settings have sensible defaults. Override what you need:
config = PostgresMemoryConfig(
user="myuser",
password="mypass",
database="mydb",
# Pool tuning (defaults shown)
pool_min_size=2,
pool_max_size=20,
pool_max_idle=300, # seconds — tune down to ~30 for serverless (Neon, Supabase)
pool_max_lifetime=1800, # seconds — tune down to ~180 for serverless
pool_timeout=30, # seconds — acquisition timeout
# Retry tuning
retry_max_attempts=3,
retry_max_wait=10, # backoff cap in seconds
)
API Reference
| Method | Description |
|---|---|
PostgresShortTerm(config) |
Constructor, takes PostgresMemoryConfig |
async with PostgresShortTerm(config) |
Opens pool, initializes checkpointer, closes on exit |
.checkpointer |
AsyncPostgresSaver instance for builder.compile(checkpointer=...) |
await .get_messages(thread_id) |
Get messages from latest checkpoint |
await .delete_thread(thread_id) |
Delete all checkpoints, blobs, and writes for a thread |
await .delete_threads_older_than(days) |
Bulk delete threads older than N days |
await .ping() |
Returns True if database is reachable |
.pool_stats() |
Pool size, available connections, waiting requests |
Testing
# Unit tests only (no database needed)
make test-unit
# Full test suite (starts Postgres via Docker, runs all tests, stops Postgres)
make test-all
# Or manually
docker compose -f tests/docker-compose.yml up -d --wait
uv run pytest --run-integration -v
docker compose -f tests/docker-compose.yml down
Acknowledgments
This project wraps langgraph-checkpoint-postgres from the LangChain team. The checkpointing engine, serialization, and schema management are entirely theirs — this library handles pool lifecycle, retry, and convenience operations on top.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file langgraph_postgres_memory-0.1.0.tar.gz.
File metadata
- Download URL: langgraph_postgres_memory-0.1.0.tar.gz
- Upload date:
- Size: 97.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.25 {"installer":{"name":"uv","version":"0.9.25","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ce7e766694b5719a5e30ea228b8b7a534d66f43e93cd58297f511a3f914828f0
|
|
| MD5 |
57233645c0c696d10750b45a1eb5d9db
|
|
| BLAKE2b-256 |
5d471b11e2cc729bb8eec1853531dc2e7391a3f0b2ddf2306e87e7c4c53b5891
|
File details
Details for the file langgraph_postgres_memory-0.1.0-py3-none-any.whl.
File metadata
- Download URL: langgraph_postgres_memory-0.1.0-py3-none-any.whl
- Upload date:
- Size: 8.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.25 {"installer":{"name":"uv","version":"0.9.25","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f9ddcc7e0db473e9b8f0b8c6d020662a278aeb4487648dc4377b58ce314f7d01
|
|
| MD5 |
36fca9785e7fd40aa8139b98760d07a0
|
|
| BLAKE2b-256 |
55a997235eb01780fd30d519e7145358ea26b6a2abbf77057abac74123b73a96
|