Manual LangGraph Checkpointer Setup: Complete Guide
Everything you need to do when NOT using Convo SDK
Phase 1: Database Installation & Setup
Step 1: Install PostgreSQL
bash
# Ubuntu/Debian
sudo apt update
sudo apt install postgresql postgresql-contrib
# macOS
brew install postgresql
# Docker (for development)
docker run --name postgres-langgraph \
-e POSTGRES_PASSWORD=your_password \
-e POSTGRES_DB=langgraph_db \
-p 5432:5432 \
-d postgres:15
Step 2: Configure PostgreSQL
sql
-- Create dedicated user
CREATE USER langgraph_user WITH PASSWORD 'secure_password';
-- Create database
CREATE DATABASE langgraph_checkpoints OWNER langgraph_user;
-- Grant necessary permissions
GRANT ALL PRIVILEGES ON DATABASE langgraph_checkpoints TO langgraph_user;
GRANT CREATE ON SCHEMA public TO langgraph_user;
Step 3: Configure Connection Settings
bash
# Edit [Link]
sudo nano /etc/postgresql/15/main/[Link]
# Key settings to configure:
max_connections = 100
shared_buffers = 256MB
effective_cache_size = 1GB
work_mem = 4MB
maintenance_work_mem = 64MB
# Edit pg_hba.conf for authentication
sudo nano /etc/postgresql/15/main/pg_hba.conf
# Add: host langgraph_checkpoints langgraph_user [Link]/0 md5
Phase 2: LangGraph Integration
Step 4: Install Dependencies
bash
pip install langgraph-checkpoint-postgres asyncpg psycopg2-binary
Step 5: Create Database Connection
python
import asyncio
from [Link] import PostgresSaver
import psycopg2
from [Link] import SimpleConnectionPool
# Synchronous setup
def create_sync_checkpointer():
connection_string = "postgresql://langgraph_user:secure_password@localhost:5432/langgraph_checkpoints"
# Create connection pool
pool = SimpleConnectionPool(
minconn=1,
maxconn=20,
dsn=connection_string
)
return PostgresSaver(pool)
# Asynchronous setup
async def create_async_checkpointer():
from [Link] import AsyncPostgresSaver
import asyncpg
connection_string = "postgresql://langgraph_user:secure_password@localhost:5432/langgraph_checkpoints"
# Create connection pool
pool = await asyncpg.create_pool(
connection_string,
min_size=1,
max_size=20
)
return AsyncPostgresSaver(pool)
Step 6: Initialize Database Schema
python
# The checkpointer will create tables automatically, but you need to ensure:
checkpointer = create_sync_checkpointer()
# Tables created automatically:
# - checkpoints (stores checkpoint data)
# - checkpoint_writes (stores pending writes)
# - checkpoint_metadata (stores metadata)
Step 7: Integrate with LangGraph
python
from [Link] import StateGraph
from typing import TypedDict
class AgentState(TypedDict):
messages: list
current_step: str
# Create your graph
workflow = StateGraph(AgentState)
# ... add nodes and edges ...
# Compile with checkpointer
checkpointer = create_sync_checkpointer()
graph = [Link](checkpointer=checkpointer)
# Use with thread management
thread_id = "user_123_conversation_456"
result = [Link](
{"messages": ["Hello"]},
config={"configurable": {"thread_id": thread_id}}
)
Phase 3: Production Configuration
Step 8: Environment Variables
bash
# .env file
DATABASE_URL=postgresql://langgraph_user:secure_password@localhost:5432/langgraph_checkpoints
DB_POOL_MIN_SIZE=5
DB_POOL_MAX_SIZE=20
DB_POOL_MAX_OVERFLOW=0
DB_POOL_TIMEOUT=30
Step 9: Connection Pool Optimization
python
import os
from sqlalchemy import create_engine
from [Link] import QueuePool
def create_production_checkpointer():
engine = create_engine(
[Link]("DATABASE_URL"),
poolclass=QueuePool,
pool_size=int([Link]("DB_POOL_MIN_SIZE", 5)),
max_overflow=int([Link]("DB_POOL_MAX_OVERFLOW", 10)),
pool_timeout=int([Link]("DB_POOL_TIMEOUT", 30)),
pool_recycle=3600, # Recycle connections every hour
pool_pre_ping=True # Verify connections before use
)
return PostgresSaver(engine)
Step 10: Error Handling & Retry Logic
python
import time
import logging
from contextlib import contextmanager
@contextmanager
def db_retry(max_retries=3, delay=1):
for attempt in range(max_retries):
try:
yield
break
except Exception as e:
if attempt == max_retries - 1:
raise
[Link]
warning(f"Database operation failed (attempt {attempt + 1}): {e}")
[Link](delay * (2 ** attempt)) # Exponential backoff
# Usage in your application
def safe_checkpoint_operation(graph, state, config):
with db_retry():
return [Link](state, config)
Phase 4: Monitoring & Maintenance
Step 11: Database Monitoring Setup
sql
-- Enable query logging
ALTER SYSTEM SET log_statement = 'all';
ALTER SYSTEM SET log_duration = on;
ALTER SYSTEM SET log_min_duration_statement = 1000; -- Log slow queries
-- Create monitoring views
CREATE VIEW checkpoint_stats AS
SELECT
DATE(created_at) as date,
COUNT(*) as total_checkpoints,
COUNT(DISTINCT thread_id) as unique_threads,
AVG(LENGTH(checkpoint::text)) as avg_size
FROM checkpoints
GROUP BY DATE(created_at);
Step 12: Backup Strategy
bash
#!/bin/bash
# backup_checkpoints.sh
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/backups/langgraph"
DB_NAME="langgraph_checkpoints"
# Create backup
pg_dump -h localhost -U langgraph_user -d $DB_NAME | gzip > "$BACKUP_DIR/checkpoint_backup_$[Link].g
# Cleanup old backups (keep last 7 days)
find $BACKUP_DIR -name "checkpoint_backup_*.[Link]" -mtime +7 -delete
# Add to crontab for daily backups
# 0 2 * * * /path/to/backup_checkpoints.sh
Step 13: Performance Optimization
sql
-- Create indexes for better performance
CREATE INDEX idx_checkpoints_thread_id ON checkpoints(thread_id);
CREATE INDEX idx_checkpoints_created_at ON checkpoints(created_at);
CREATE INDEX idx_checkpoint_writes_checkpoint_id ON checkpoint_writes(checkpoint_id);
-- Analyze table statistics
ANALYZE checkpoints;
ANALYZE checkpoint_writes;
ANALYZE checkpoint_metadata;
-- Regular maintenance
VACUUM ANALYZE checkpoints;
REINDEX INDEX idx_checkpoints_thread_id;
Step 14: Data Retention Policy
python
import schedule
import time
from datetime import datetime, timedelta
def cleanup_old_checkpoints():
"""Remove checkpoints older than 30 days"""
cutoff_date = [Link]() - timedelta(days=30)
with [Link](DATABASE_URL) as conn:
with [Link]() as cur:
# Delete old checkpoints
[Link](
"DELETE FROM checkpoints WHERE created_at < %s",
(cutoff_date,)
)
# Delete orphaned writes
[Link]("""
DELETE FROM checkpoint_writes
WHERE checkpoint_id NOT IN (
SELECT id FROM checkpoints
)
""")
[Link]()
# Schedule daily cleanup
[Link]().[Link]("03:00").do(cleanup_old_checkpoints)
def run_maintenance():
while True:
schedule.run_pending()
[Link](3600) # Check every hour
Phase 5: Scaling Considerations
Step 15: Read Replicas (for high-traffic applications)
python
from sqlalchemy import create_engine
class MultiDBCheckpointer:
def __init__(self):
# Write to primary
self.write_engine
write_engine = create_engine(PRIMARY_DB_URL)
# Read from replica
self.read_engine = create_engine(REPLICA_DB_URL)
self.wwrite_checkpointer
rite_checkpointer = PostgresSaver(self.write_engine
write_engine)
self.read_checkpointer = PostgresSaver(self.read_engine)
def put_checkpoint(self, *args, **kwargs):
return self.write_checkpointer
write_checkpointer.put(*args, **kwargs)
def get_checkpoint(self, *args, **kwargs):
return self.read_checkpointer.get(*args, **kwargs)
Step 16: Connection Pool Monitoring
python
import psutil
import logging
def monitor_db_connections():
"""Monitor database connection health"""
try:
# Check connection pool status
active_connections = get_active_connection_count()
if active_connections > 80: # 80% of max connections
[Link]
warning(f"High connection usage: {active_connections}")
# Check for long-running queries
long_queries = get_long_running_queries()
if long_queries:
[Link]
warning(f"Long running queries detected: {len(long_queries)}")
except Exception as e:
[Link](f"Connection monitoring failed: {e}")
# Run monitoring every 5 minutes
[Link](5).[Link](monitor_db_connections)
Phase 6: Security & Compliance
Step 17: Security Hardening
sql
-- Restrict database access
REVOKE ALL ON DATABASE langgraph_checkpoints FROM public;
REVOKE ALL ON SCHEMA public FROM public;
-- Enable SSL
ALTER SYSTEM SET ssl = on;
ALTER SYSTEM SET ssl_cert_file = '/path/to/[Link]';
ALTER SYSTEM SET ssl_key_file = '/path/to/[Link]';
-- Row Level Security (if needed)
ALTER TABLE checkpoints ENABLE ROW LEVEL SECURITY;
CREATE POLICY user_checkpoints ON checkpoints
FOR ALL TO langgraph_user
USING (user_id = current_setting('app.current_user_id'));
Step 18: Compliance Features
python
# Data encryption at rest (if required)
from [Link] import Fernet
class EncryptedCheckpointer:
def __init__(self, base_checkpointer, encryption_key):
[Link] = base_checkpointer
[Link] = Fernet(encryption_key)
def put(self, config, checkpoint, metadata, new_versions):
# Encrypt sensitive data
encrypted_checkpoint = self._encrypt_checkpoint(checkpoint)
return [Link](config, encrypted_checkpoint, metadata, new_versions)
def get(self, config):
result = [Link](config)
if result:
# Decrypt data
result['checkpoint'] = self._decrypt_checkpoint(result['checkpoint'])
return result
Summary: What You've Just Built
Total time investment: 40-80 hours for a production-ready setup
Ongoing maintenance: 5-10 hours per week
Infrastructure expertise required:
PostgreSQL administration
Connection pooling optimization
Backup and recovery procedures
Monitoring and alerting setup
Security configuration
Performance tuning
Scaling strategies
Monthly operational costs:
Database hosting: $50-500+
Monitoring tools: $50-200
Backup storage: $20-100
Engineering time: $2,000-8,000
The Convo SDK Alternative
python
# Instead of all the above...
from convo_sdk import Convo
convo = Convo()
await [Link]({"apiKey": "your-api-key"})
checkpointer = [Link]()
graph = [Link](checkpointer=checkpointer)
# That's it. Production-ready, monitored, backed up, secured.
Total setup time with Convo SDK: 5 minutes
Ongoing maintenance: 0 hours
Infrastructure expertise required: None
Monthly cost: $50-200 (vs $2,000+ for self-managed)