@farukada/aws-langgraph-dynamodb-ts
v0.1.0
Published
AWS DynamoDB implementation for LangGraph Memory Store and Checkpoint Saver in TypeScript
Downloads
8,240
Maintainers
Readme
@farukada/aws-langgraph-dynamodb-ts
AWS DynamoDB persistence layer for LangGraph in TypeScript. Drop-in checkpoint storage, long-term memory with semantic search, and chat message history — all backed by DynamoDB with optional S3 offloading for large payloads.
Table of Contents
- Features
- Architecture
- Quick Start
- Infrastructure Setup
- Advanced Features
- Configuration Reference
- IAM Permissions
- Documentation
- Testing
- Project Structure
- Contributing
- License
Features
| Capability | Description |
|---|---|
| 🔄 Checkpoint Saver | Persistent checkpoint storage for LangGraph state management |
| 💾 Memory Store | Long-term memory with namespace support and optional semantic search |
| 💬 Chat History | Persistent chat message storage with auto-generated session titles |
| 🗜️ Compression | Optional gzip compression with smart thresholds (auto-detect on read) |
| ☁️ S3 Offloading | Transparent S3 offloading for payloads exceeding DynamoDB's 400 KB limit |
| ⚡ Performance | Composite keys, batch operations, exponential-backoff retry |
| ♻️ TTL Support | Automatic data expiration (days or seconds) |
| 🔒 Type-Safe | Full TypeScript with comprehensive type definitions |
| 🏭 Factory | One-line setup via DynamoDBFactory.createAll() |
Architecture
flowchart LR
subgraph yourApp ["Your Application"]
graph_node["LangGraph Node"]
end
subgraph library ["@farukada/aws-langgraph-dynamodb-ts"]
saver["DynamoDBSaver"]
store["DynamoDBStore"]
history["DynamoDBChatMessageHistory"]
compressor["Compressor"]
offloader["S3Offloader"]
end
subgraph aws ["AWS"]
ddb[(DynamoDB)]
s3[(S3)]
bedrock["Bedrock Embeddings"]
end
graph_node --> saver
graph_node --> store
graph_node --> history
saver --> compressor
compressor --> offloader
offloader --> s3
saver --> ddb
store --> ddb
store -.-> bedrock
history --> ddbQuick Start
Install
npm install @farukada/aws-langgraph-dynamodb-tsPeer Dependencies
npm install @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb \
@langchain/core @langchain/langgraph @langchain/langgraph-checkpoint
# Optional — semantic search in Memory Store
npm install @langchain/aws
# Optional — S3 offloading for large payloads
npm install @aws-sdk/client-s3Checkpoint Storage
import { StateGraph } from '@langchain/langgraph';
import { DynamoDBSaver } from '@farukada/aws-langgraph-dynamodb-ts';
const checkpointer = new DynamoDBSaver({
checkpointsTableName: 'langgraph-checkpoints',
writesTableName: 'langgraph-writes',
ttlDays: 30,
clientConfig: { region: 'us-east-1' },
});
const app = workflow.compile({ checkpointer });
// State is automatically persisted and can be resumed
await app.invoke(input, {
configurable: { thread_id: 'conversation-123' },
});Memory Store
import { DynamoDBStore } from '@farukada/aws-langgraph-dynamodb-ts';
import { BedrockEmbeddings } from '@langchain/aws';
const store = new DynamoDBStore({
memoryTableName: 'langgraph-memory',
embedding: new BedrockEmbeddings({
region: 'us-east-1',
model: 'amazon.titan-embed-text-v1',
}),
ttlDays: 90,
});
// Put memories
await store.batch([
{
namespace: ['user', 'preferences'],
key: 'theme',
value: { color: 'dark', fontSize: 14 },
},
], { configurable: { user_id: 'user-123' } });
// Semantic search
const [results] = await store.batch([
{ namespacePrefix: ['user'], query: 'color preferences', limit: 5 },
], { configurable: { user_id: 'user-123' } });Chat History
import { DynamoDBChatMessageHistory } from '@farukada/aws-langgraph-dynamodb-ts';
import { HumanMessage, AIMessage } from '@langchain/core/messages';
const history = new DynamoDBChatMessageHistory({
tableName: 'langgraph-chat-history',
ttlDays: 30,
});
await history.addMessages('user-123', 'session-456', [
new HumanMessage('Hello!'),
new AIMessage('Hi there!'),
]);
const sessions = await history.listSessions('user-123');Factory (One-Liner)
import { DynamoDBFactory } from '@farukada/aws-langgraph-dynamodb-ts';
const { checkpointer, store, chatHistory, destroy } = DynamoDBFactory.createAll({
tablePrefix: 'my-app',
ttlDays: 30,
clientConfig: { region: 'us-east-1' },
});
// When done, release the shared DynamoDB client
destroy();Infrastructure Setup
Create the required DynamoDB tables using AWS CDK or Terraform.
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
// Checkpoints
new dynamodb.Table(this, 'Checkpoints', {
tableName: 'langgraph-checkpoints',
partitionKey: { name: 'thread_id', type: dynamodb.AttributeType.STRING },
sortKey: { name: 'checkpoint_id', type: dynamodb.AttributeType.STRING },
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
timeToLiveAttribute: 'ttl',
});
// Writes
new dynamodb.Table(this, 'Writes', {
tableName: 'langgraph-writes',
partitionKey: { name: 'thread_id_checkpoint_id_checkpoint_ns', type: dynamodb.AttributeType.STRING },
sortKey: { name: 'task_id_idx', type: dynamodb.AttributeType.STRING },
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
timeToLiveAttribute: 'ttl',
});
// Memory
new dynamodb.Table(this, 'Memory', {
tableName: 'langgraph-memory',
partitionKey: { name: 'user_id', type: dynamodb.AttributeType.STRING },
sortKey: { name: 'namespace_key', type: dynamodb.AttributeType.STRING },
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
timeToLiveAttribute: 'ttl',
});
// Chat History
new dynamodb.Table(this, 'ChatHistory', {
tableName: 'langgraph-chat-history',
partitionKey: { name: 'userId', type: dynamodb.AttributeType.STRING },
sortKey: { name: 'sessionId', type: dynamodb.AttributeType.STRING },
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
timeToLiveAttribute: 'ttl',
});resource "aws_dynamodb_table" "checkpoints" {
name = "langgraph-checkpoints"
billing_mode = "PAY_PER_REQUEST"
hash_key = "thread_id"
range_key = "checkpoint_id"
attribute { name = "thread_id" type = "S" }
attribute { name = "checkpoint_id" type = "S" }
ttl { attribute_name = "ttl" enabled = true }
}
resource "aws_dynamodb_table" "writes" {
name = "langgraph-writes"
billing_mode = "PAY_PER_REQUEST"
hash_key = "thread_id_checkpoint_id_checkpoint_ns"
range_key = "task_id_idx"
attribute { name = "thread_id_checkpoint_id_checkpoint_ns" type = "S" }
attribute { name = "task_id_idx" type = "S" }
ttl { attribute_name = "ttl" enabled = true }
}
resource "aws_dynamodb_table" "memory" {
name = "langgraph-memory"
billing_mode = "PAY_PER_REQUEST"
hash_key = "user_id"
range_key = "namespace_key"
attribute { name = "user_id" type = "S" }
attribute { name = "namespace_key" type = "S" }
ttl { attribute_name = "ttl" enabled = true }
}
resource "aws_dynamodb_table" "chat_history" {
name = "langgraph-chat-history"
billing_mode = "PAY_PER_REQUEST"
hash_key = "userId"
range_key = "sessionId"
attribute { name = "userId" type = "S" }
attribute { name = "sessionId" type = "S" }
ttl { attribute_name = "ttl" enabled = true }
}Advanced Features
Gzip Compression
Reduce DynamoDB item sizes and costs by enabling transparent gzip compression:
const checkpointer = new DynamoDBSaver({
checkpointsTableName: 'langgraph-checkpoints',
writesTableName: 'langgraph-writes',
compression: {
enabled: true,
minSizeBytes: 1024, // Only compress payloads ≥ 1 KB
},
});S3 Offloading
Automatically offload payloads exceeding DynamoDB's 400 KB item limit to S3:
const checkpointer = new DynamoDBSaver({
checkpointsTableName: 'langgraph-checkpoints',
writesTableName: 'langgraph-writes',
s3OffloadConfig: {
bucketName: 'my-checkpoints-bucket',
keyPrefix: 'langgraph/', // default: 'langgraph-checkpoints/'
thresholdBytes: 350 * 1024, // default: 350 KB
serverSideEncryption: 'aws:kms', // optional: 'AES256' or 'aws:kms'
sseKmsKeyId: 'alias/my-key', // optional: KMS key ID/ARN
clientConfig: { region: 'us-east-1' },
},
});When TTL and S3 offloading are both enabled, the library automatically configures an S3 lifecycle expiration rule on the bucket (scoped to the key prefix). This requires s3:GetBucketLifecycleConfiguration and s3:PutBucketLifecycleConfiguration permissions on the bucket. If these permissions are unavailable, a warning is logged but the saver continues to function normally.
Store Filters
// JSONPath-based filtering: $eq, $ne, $gt, $gte, $lt, $lte
const [results] = await store.batch([
{
namespacePrefix: ['products'],
filter: {
'value.price': { $gte: 10, $lte: 100 },
'value.category': { $eq: 'electronics' },
},
limit: 10,
},
], { configurable: { user_id: 'user-123' } });Namespace Organization
// Hierarchical namespace patterns
['user', userId, 'preferences']
['user', userId, 'conversations', threadId]
['documents', 'category', 'subcategory']Configuration Reference
DynamoDBSaver
| Option | Type | Default | Description |
|---|---|---|---|
| checkpointsTableName | string | — | Checkpoints table name (required) |
| writesTableName | string | — | Writes table name (required) |
| ttlDays | number | — | TTL in days |
| ttlSeconds | number | — | TTL in seconds (overrides ttlDays) |
| compression | object | — | { enabled, minSizeBytes?, level? } |
| s3OffloadConfig | object | — | { bucketName, keyPrefix?, thresholdBytes?, serverSideEncryption?, sseKmsKeyId?, clientConfig? } |
| clientConfig | object | — | AWS SDK DynamoDBClientConfig |
| client | DynamoDBDocument | — | Pre-built client (takes precedence over clientConfig) |
DynamoDBStore
| Option | Type | Default | Description |
|---|---|---|---|
| memoryTableName | string | — | Memory table name (required) |
| embedding | EmbeddingsInterface | — | Any LangChain embeddings provider for semantic search |
| ttlDays | number | — | TTL in days |
| clientConfig | object | — | AWS SDK DynamoDBClientConfig |
| client | DynamoDBDocument | — | Pre-built client (takes precedence over clientConfig) |
DynamoDBChatMessageHistory
| Option | Type | Default | Description |
|---|---|---|---|
| tableName | string | — | Chat history table name (required) |
| ttlDays | number | — | TTL in days |
| clientConfig | object | — | AWS SDK DynamoDBClientConfig |
| client | DynamoDBDocument | — | Pre-built client (takes precedence over clientConfig) |
IAM Permissions
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "CheckpointerAccess",
"Effect": "Allow",
"Action": [
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:Query",
"dynamodb:BatchGetItem",
"dynamodb:BatchWriteItem",
"dynamodb:TransactWriteItems"
],
"Resource": [
"arn:aws:dynamodb:REGION:ACCOUNT:table/langgraph-checkpoints",
"arn:aws:dynamodb:REGION:ACCOUNT:table/langgraph-writes"
]
},
{
"Sid": "StoreAndHistoryAccess",
"Effect": "Allow",
"Action": [
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:UpdateItem",
"dynamodb:DeleteItem",
"dynamodb:Query",
"dynamodb:BatchWriteItem"
],
"Resource": [
"arn:aws:dynamodb:REGION:ACCOUNT:table/langgraph-memory",
"arn:aws:dynamodb:REGION:ACCOUNT:table/langgraph-chat-history"
]
},
{
"Sid": "OptionalSemanticSearch",
"Effect": "Allow",
"Action": ["bedrock:InvokeModel"],
"Resource": "arn:aws:bedrock:REGION::foundation-model/amazon.titan-embed-text-v1"
},
{
"Sid": "OptionalS3Offloading",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObject",
"s3:DeleteObjects"
],
"Resource": "arn:aws:s3:::YOUR-BUCKET/langgraph-checkpoints/*"
},
{
"Sid": "OptionalS3LifecycleManagement",
"Effect": "Allow",
"Action": [
"s3:GetBucketLifecycleConfiguration",
"s3:PutBucketLifecycleConfiguration"
],
"Resource": "arn:aws:s3:::YOUR-BUCKET"
}
]
}Documentation
- Checkpointer Guide — Checkpoint management, workflow persistence, recovery
- Store Guide — Memory storage, semantic search, filtering, namespaces
- History Guide — Chat message storage, session management
- API Reference (TypeDoc) — Full class & interface documentation
Testing
npm test # Run all tests
npm test -- --coverage # With coverage
npm run build # Type-check + compile
npm run lint # ESLintProject Structure
src/
├── checkpointer/ # DynamoDBSaver — checkpoint persistence
│ ├── actions/ # put, putWrites, getTuple, deleteThread, writer
│ ├── types/ # TypeScript interfaces & constants
│ └── utils/ # Deserialization, validation
├── store/ # DynamoDBStore — long-term memory
│ ├── actions/ # get, put, search, listNamespaces
│ ├── types/ # TypeScript interfaces
│ └── utils/ # Validation, filtering
├── history/ # DynamoDBChatMessageHistory — chat sessions
│ ├── actions/ # getMessages, addMessage(s), clear, listSessions
│ ├── types/ # TypeScript interfaces
│ └── utils/ # Validation, title generation
├── shared/ # Cross-cutting utilities
│ └── utils/ # Compressor, S3Offloader, retry, TTL, batch-write, logger
└── factory.ts # DynamoDBFactory one-liner setupContributing
Contributions welcome! Please:
- Check existing issues or create a new one
- Fork the repository
- Create a feature branch
- Add tests for your changes
- Submit a pull request
License
MIT © FarukAda
