DynamoDB Provider¶
strands-session-dynamodb is an Amazon DynamoDB storage backend for Strands Agents. It implements the core SessionStorage interface, so all of the session lifecycle logic — message indexing, restore, removed_message_count offsetting, tool-use repair, and change detection — is reused unchanged from the core. This package supplies only the DynamoDB storage.
Storage only, by design
Message pruning in Strands is the job of a ConversationManager (SlidingWindow, Summarizing), deliberately decoupled from storage. This package does not prune — pruning at the storage layer would corrupt Strands' message-index/offset restore logic. Use a conversation_manager for that.
Installation¶
Requires Python 3.10+.
Why DynamoDB instead of S3¶
Strands ships an S3SessionManager out of the box, so why DynamoDB? Because agent sessions are a request-bound, small-item workload — the exact shape where DynamoDB wins on both cost and latency.
Strands writes one item per message plus an agent record re-synced each turn — lots of tiny (sub-KB) reads and writes. The bill is dominated by request count, not bytes stored, and that is where the two services price very differently:
| S3 Standard | DynamoDB on-demand | |
|---|---|---|
| Write | ~$5.00 / million PUT (any size) | ~$1.25 / million WRU (per 1 KB) |
| Read | ~$0.40 / million GET (per object) | ~$0.25 / million RRU (per 4 KB) |
| Free tier | none | 25 WCU + 25 RCU + 25 GB, perpetual |
| Latency | tens of ms | single-digit ms |
Two structural advantages for small items:
- Writes: S3 charges per request regardless of size — a 200-byte message costs the same PUT as a 4 MB one. DynamoDB bills per KB, so tiny messages hit the cheapest unit and the per-unit price is ~4x lower.
- Reads:
list_messagesis one Query in DynamoDB, and one RRU covers 4 KB — so several small messages per RRU. In S3 it is one GET per message object. Batching crushes the per-item read cost.
For a workload of ~1M small message-writes/month with periodic restores, this is roughly a 3–4x lower bill on DynamoDB — and often free under DynamoDB's perpetual free tier, which S3 has no equivalent of. Add native TTL for automatic session expiry and single-digit-ms access, and DynamoDB is the better default for hot session/agent-state storage.
When S3 still wins
Very large message payloads (big tool results, images) that approach or exceed DynamoDB's 400 KB item limit, or cold/archival sessions rarely read (S3 storage is ~10x cheaper per GB). A robust production setup is DynamoDB for the session/message records + S3 overflow only for oversized blobs.
Quick start¶
from strands import Agent
from strands_session_dynamodb import DynamoDBSessionManager
session_manager = DynamoDBSessionManager(
session_id="user-123",
table_name="strands-sessions",
region_name="us-east-1",
)
agent = Agent(session_manager=session_manager)
agent("Hi, I'm Kamal")
agent("What's my name?") # remembers within the session
Next run, same session_id → the agent restores its full history and state from DynamoDB. The table is created automatically (on-demand billing) if it does not exist.
Constructor parameters¶
DynamoDBSessionManager(session_id, table_name, *, region_name=None, boto_session=None, boto_client_config=None, endpoint_url=None, ttl_seconds=None)
| Parameter | Description |
|---|---|
session_id |
Session identifier |
table_name |
DynamoDB table (auto-created if absent) |
region_name |
AWS region |
boto_session |
Optional pre-built boto3.Session |
boto_client_config |
Optional botocore client config |
endpoint_url |
Custom endpoint (e.g. DynamoDB Local / LocalStack) |
ttl_seconds |
If set, writes a ttl epoch attribute and enables table TTL for automatic session expiry |
The table is auto-created with on-demand billing on first use if it does not already exist. For credential resolution and the full auth surface, see Authentication.
Data model¶
Single table, both keys strings:
| Item | PK | SK |
|---|---|---|
| Session | SESSION#<session_id> |
META |
| Agent | SESSION#<session_id> |
AGENT#<agent_id> |
| Message | SESSION#<session_id>#AGENT#<agent_id> |
MSG#<zero-padded id> |
Messages live in a per-agent partition with a zero-padded, lexically ordered sort key, so list_messages(offset, limit) is a native range Query — matching the removed_message_count offset semantics Strands relies on. Payloads are stored as a JSON string.
Item-size cap: 400 KB
DynamoDB items are capped at 400 KB. A single message with a very large payload (big tool results / images) could exceed that; S3 has no such limit. For those workloads, keep large blobs in S3 and reference them.
See also¶
- What You Get — the shared
SessionStoragecontract this provider implements. - Build Your Own Backend — write a storage backend of your own.
- Authentication — the full boto3 credential surface.
Version 0.1.0 · MIT License