Separate Long term memory and Checkpointing

I have been using langgraph in production at my company for few months now. I am using a custom checkpointer with postgres since I didn’t require everything that langgraph-postgres-checkpointer offers. I am still struggling to understand difference between checkpointing and long term memory. These topics or so tightly couples in langgraph that it is impossible for me to just use one. I don’t want to do replays or resuming from a point, I just want to understand how I can only keep single row in database per execution of graph which have list of messages. Currently every execution of graph creates about 50 rows with each step. Is there any documentation or plan to simplify and uncouple these concepts in future?

1 Like

Hi @ritik

very good question!

  • Checkpointing (persistence): per‑step snapshots of the graph state so you can resume/time‑travel/human‑in‑the‑loop within a single run. By design, this yields multiple records - roughly one per step. See the docs: Checkpointing/Persistence.
  • Long‑term memory: cross‑run, cross‑thread storage of facts/preferences you want to recall later. It’s not tied to resumption and can live in any store (e.g., Postgres/SQLite/Vector). See the docs: Memory.

Why are you seeing ~50 rows per execution?

  • That’s normal for checkpointing: the engine writes a new checkpoint at each step to enable safe resume and time‑travel. Postgres checkpointers use a (thread_id, checkpoint_ns, checkpoint_id, parent_id) model that intentionally creates many rows.

If you don’t want replays/resume and only want 1 row per execution with all messages:

  • Option A: Don’t use a checkpointer. Run the graph without a checkpointer, stream events, aggregate messages, and write a single row at the end. You keep zero per‑step rows and still get a complete transcript.
  • Option B: Use a “compacting” custom checkpointer. Implement your checkpointer so put always upserts the same row keyed by your (run_id/thread_id) and stores the latest state/messages. You’ll lose time‑travel but keep a single evolving row per run.
  • Option C: Post‑run compaction. Use a standard checkpointer during execution, then on the terminal event copy the final state/messages into a “runs” table (1 row), and prune intermediate checkpoints for that run.

Are checkpointing and long‑term memory coupled?

  • Conceptually they are separate. The server/threads UX leans on checkpointing, but the library lets you use memory without checkpointing (and vice‑versa). There isn’t a public roadmap promising a single‑row checkpointer; current guidance is to choose one of the patterns above based on whether you need resume/time‑travel.

Handy references


@ritik does this add up and clarify the issue?

1 Like