How to handle growing checkpoint blob?

I’m using open-source LangGraph with PostgresSaver and durability: "exit".

The checkpoints table looks fine for my use case since I’m seeing roughly one checkpoint per chat request. The issue is that checkpoint_blobs keeps growing much faster over time.

For people running LangGraph with Postgres in production, how do you usually manage this growth?

Do you periodically delete older blobs/checkpoints after some retention period, keep only the latest N checkpoints per thread, or use another cleanup strategy?

I still want checkpoint durability, but I don’t need unlimited historical checkpoint data for every conversation.

Would appreciate hearing how others handle checkpoint retention and database size in the open-source libraries.

Why checkpoint_blobs grows faster

Large channel values (messages, state fields) are stored in checkpoint_blobs, not in the checkpoints row itself. With durability: "exit" you get about one checkpoint per request, but each run can still create new blob versions for changed channels. See Checkpointers for how checkpoints and blobs relate.

What the docs recommend

  1. Prune old history, keep current state. The Persistence guide calls this out under “Checkpoints growing unboundedly”: prune periodically or set a retention policy. Use checkpointer.prune(thread_ids, strategy="keep_latest"), which keeps the latest checkpoint per namespace and removes older checkpoints, blobs, and writes together. API: BaseCheckpointSaver.prune.

  2. Delete finished conversations entirely. The Memory guide documents checkpointer.delete_thread(thread_id) under “Delete all checkpoints for a thread”. Use this for threads you no longer need, or run it on a schedule for threads older than your retention window.

  3. Do not manually delete from checkpoint_blobs or checkpoint_writes. Use prune or delete_thread so cleanup stays consistent with LangGraph’s internal model (including time travel and resume).

  4. If you run LangGraph Server / Agent Server, configure TTL in langgraph.json with strategy: "keep_latest". That keeps the thread and latest checkpoint per namespace and removes older data automatically. See Configure TTL.

  5. If you use DeltaChannel, read the pruning section in Checkpointers. Naive keep_latest can break delta channel reconstruction if it drops ancestor writes the surviving checkpoint still depends on.

Typical self-hosted pattern

Keep durability for active threads. After a conversation completes (no pending interrupts), call prune(..., strategy="keep_latest"). For expired threads, call delete_thread. That limits DB growth without losing the ability to resume active conversations.

@hks just checking up, if the confusion is now clear?