# How Open Notebook Uses SQLite Checkpoint Files to Persist LangGraph State

> Learn how Open Notebook uses SQLite checkpoint files to persist LangGraph state. Survive server restarts and resume AI workflows exactly where they left off.

- Repository: [Luis Novo/open-notebook](https://github.com/lfnovo/open-notebook)
- Tags: how-to-guide
- Published: 2026-06-15

---

**Open Notebook persists LangGraph state by writing runtime checkpoints to a dedicated SQLite database, allowing AI workflows to survive server restarts and resume exactly where they left off.**

Open Notebook builds its LangGraph workflows (such as the *source-chat* and *chat* graphs) on top of **LangGraph’s SQLite checkpoint system**. By configuring a file-based SQLite database to store state snapshots, the application ensures that long-running conversations and complex multi-step processes remain durable across process crashes or redeployments. This implementation leverages the `SqliteSaver` class from LangGraph’s checkpoint module, binding each compiled graph to a persistent database connection that automatically serializes state changes.

## Checkpoint File Configuration

The location of the SQLite database is defined centrally in [`open_notebook/config.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/config.py). The project constructs the checkpoint file path by appending the database filename to a dedicated SQLite folder:

```python

# open_notebook/config.py

LANGGRAPH_CHECKPOINT_FILE = f"{sqlite_folder}/checkpoints.sqlite"

```

Here, `sqlite_folder` points to the repository’s `data/sqlite-db/` directory. This centralized configuration ensures that all graph workflows reference the same persistent storage location, creating a single source of truth for runtime state across the entire application.

## Setting Up the SQLite Saver

In each graph module, Open Notebook establishes a SQLite connection optimized for multi-threaded access and wraps it with `SqliteSaver`. This pattern appears in [`open_notebook/graphs/source_chat.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/source_chat.py) and [`open_notebook/graphs/chat.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/chat.py), where the connection explicitly disables thread checking to support concurrent workflow execution:

```python

# open_notebook/graphs/source_chat.py

import sqlite3
from langgraph.checkpoint.sqlite import SqliteSaver
from open_notebook.config import LANGGRAPH_CHECKPOINT_FILE

# Enable cross-thread access for async/concurrent execution

conn = sqlite3.connect(
    LANGGRAPH_CHECKPOINT_FILE,
    check_same_thread=False,
)
memory = SqliteSaver(conn)

```

The `check_same_thread=False` parameter is critical for production deployments where LangGraph nodes may execute across different threads or async contexts. `SqliteSaver` manages the actual synchronization, ensuring that state writes are atomic and safe despite the relaxed thread constraints.

## Compiling Graphs with Persistence

Once the saver is instantiated, it is injected into the graph at compile time via the `checkpointer` parameter. In [`open_notebook/graphs/source_chat.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/source_chat.py), the workflow constructs a `StateGraph` using a custom TypedDict (e.g., `SourceChatState`), defines node transitions, and then compiles with the SQLite-backed memory:

```python

# open_notebook/graphs/source_chat.py

from langgraph.graph import StateGraph, START, END

source_chat_state = StateGraph(SourceChatState)
source_chat_state.add_node("source_chat_agent", call_model_with_source_context)
source_chat_state.add_edge(START, "source_chat_agent")
source_chat_state.add_edge("source_chat_agent", END)

# Compile with SQLite persistence enabled

source_chat_graph = source_chat_state.compile(checkpointer=memory)

```

The same compilation pattern appears in [`open_notebook/graphs/chat.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/chat.py), where the `SqliteSaver` instance is passed to `agent_state.compile()` to enable checkpointing for the generic chat workflow. This binding ensures that every node transition automatically triggers a state snapshot write to the underlying database.

## What Gets Stored in the Database

`SqliteSaver` automatically serializes the graph’s state—defined by the TypedDict (such as `SourceChatState`)—into a SQLite table named `checkpoints`. The data is stored as JSON, which safely handles complex Python objects including:

- **Lists of messages** (conversation history)
- **Source IDs** (references to documents or context)
- **Model overrides** (runtime configuration changes)
- **Custom state fields** (application-specific metadata)

This JSON serialization ensures that even nested data structures survive the round-trip to disk, maintaining the exact runtime context required to resume execution.

## Restoring Workflow Sessions

When a client reconnects or a server process restarts, the graph loads the latest checkpoint from the SQLite file and reconstructs the state dictionary. This restoration happens transparently when invoking the graph with a consistent configuration identifier:

```python

# Example: Resuming a conversation using the saved checkpoint

result = await chat_graph.ainvoke(
    {"messages": [], "user_id": "alice"},
    config={"configurable": {"run_id": "session-123"}}
)

```

By specifying a stable `run_id` in the configuration, the graph identifies the correct checkpoint row in the database, hydrates the state object, and continues execution exactly where the previous session terminated. This mechanism makes Open Notebook’s AI workflows resilient against infrastructure failures and suitable for long-running background tasks like podcast generation or extended source analysis.

## Summary

- **SQLite checkpoint files** provide durable persistence for LangGraph state machines in Open Notebook, surviving process restarts and crashes.
- **Configuration** is centralized in [`open_notebook/config.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/config.py) via the `LANGGRAPH_CHECKPOINT_FILE` variable, which points to `data/sqlite-db/checkpoints.sqlite`.
- **Thread-safe connections** are established with `check_same_thread=False` and wrapped in `SqliteSaver` to support concurrent workflow execution.
- **Graph compilation** requires passing the saver to `compile(checkpointer=memory)`, enabling automatic state serialization at every node transition.
- **JSON serialization** in the `checkpoints` table preserves complex objects like message lists and source metadata.
- **Session restoration** works by loading the latest checkpoint based on the run configuration, allowing workflows to resume seamlessly without data loss.

## Frequently Asked Questions

### Where is the checkpoint file located in Open Notebook?

The checkpoint file path is defined in [`open_notebook/config.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/config.py) as `LANGGRAPH_CHECKPOINT_FILE`, which resolves to `data/sqlite-db/checkpoints.sqlite` within the project repository. This centralized definition ensures that all graph modules reference the same persistent database.

### Why does the SQLite connection use `check_same_thread=False`?

LangGraph workflows often execute across multiple threads or async contexts, especially when handling concurrent user requests. Setting `check_same_thread=False` allows the same SQLite connection to be shared safely across these execution contexts, while `SqliteSaver` internally manages synchronization to prevent race conditions.

### What happens if the SQLite checkpoint file is deleted?

If the checkpoint file is removed or corrupted, all persisted state is permanently lost. Active workflows cannot be resumed and will initialize from their default state on the next invocation. Open Notebook treats the SQLite database as the authoritative source of truth for runtime state.

### Can I migrate from SQLite to another checkpoint backend?

While Open Notebook currently relies on `SqliteSaver` from `langgraph.checkpoint.sqlite`, LangGraph supports alternative checkpointer implementations such as Postgres or Redis. Migrating would require replacing the connection setup and saver instantiation in [`open_notebook/graphs/source_chat.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/source_chat.py) and [`open_notebook/graphs/chat.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/chat.py) with the appropriate backend-specific checkpointer class.