We are planning to use @langchain/langgraph-checkpoint-postgres in a production Node.js service and have a few questions about the recommended database ownership and retention model.
Our service team normally owns all PostgreSQL schema migrations. However, PostgresSaver.setup() creates/updates the LangGraph checkpoint tables and manages checkpoint_migrations.
For production, is the recommended approach to:
Run checkpointer.setup() as a separate deployment/migration step before starting the application, and not call it during normal application startup?
Or is it supported/recommended for the service team to copy the LangGraph PostgreSQL migrations into our own Node service migration framework and manage the tables ourselves?
We also need a configurable retention period, for example 30/60/90 days. I do not see a retention/TTL option in PostgresSaver.
What is the recommended production approach for cleaning up old checkpoint data?
Is deleting an entire inactive thread with deleteThread(threadId) the recommended approach?
Is there a supported way to retain only the last N days/checkpoints for an active thread?
Are there any dependencies between checkpoints, checkpoint_blobs, and checkpoint_writes that make manual pruning unsafe?
Finally, are there any recommended monitoring or sizing guidelines for these four tables?
checkpoint_migrations
checkpoints
checkpoint_blobs
checkpoint_writes
We want to make sure our migration, retention, and storage strategy is production-safe before adopting PostgresSaver.
Hello @waiz-ksolves,
For a self-hosted Node.js service using @langchain/langgraph-checkpoint-postgres directly (not Agent Server):
Migrations: The add-memory docs note that checkpointer.setup() must be called the first time. Running setup() as a one-time deployment/migration step (before app startup) is a reasonable production pattern. The docs do not describe copying LangGraph SQL into a separate migration framework, setup() is the supported path for schema creation and updates via checkpoint_migrations.
Retention:PostgresSaver has no built-in TTL. The persistence docs recommend pruning old checkpoints periodically (e.g. a cron job). Built-in TTL (delete / keep_latest) is an Agent Server feature configured in langgraph.json, not in the standalone checkpointer library.
Cleanup:
For inactive threads, deleteThread(threadId) is the supported API — it removes all checkpoint and write rows for that thread (checkpointers docs).
There is no documented way to retain only the last N days/checkpoints for an active thread when using the library directly. Agent Server’s keep_latest strategy covers that use case.
Manual SQL deletes across checkpoints, checkpoint_blobs, and checkpoint_writes are risky, prefer the checkpointer APIs so related rows stay consistent.
Monitoring: The docs do not publish sizing guidelines for those tables. Standard Postgres monitoring (row counts, table/index size, write latency) is the practical approach.
This is a really good set of questions. I’ve been looking at similar concerns around productionizing LangGraph workflows, especially around who should own state persistence and how to avoid checkpoint tables growing forever.
I’d also be interested to hear what the LangGraph team recommends here. In practice, I’d probably prefer keeping schema ownership inside the service migration flow rather than having startup code mutate production schemas, but curious if there are edge cases with checkpoint migrations that make setup() the better option.
The retention part is especially interesting, have you found any guidance on safe pruning strategies for active threads?