Skip to content

Lesson 9: Persistent memory with session managers

Play

Watch on YouTube

Code for this lesson: samples/09-persistent-memory

Session managers persist conversation history and agent state across runs. Without them, everything resets when the process stops. They’re implemented as hook providers, so persistence is just another harness behavior layered in through hooks.

Run these examples from samples/09-persistent-memory.

The record-based approach persists each message individually. It’s still supported for existing sessions and available for existing record-based Graph/Swarm sessions.

from strands import Agent
from strands.session.file_session_manager import FileSessionManager
from customer_service_tools import lookup_customer, get_order_history, process_refund
SYSTEM_PROMPT = "Help customers with their orders using the available tools."
session_manager = FileSessionManager(
session_id="customer-session-001",
storage_dir="./sessions",
)
agent = Agent(
tools=[lookup_customer, get_order_history, process_refund],
system_prompt=SYSTEM_PROMPT,
context_manager="auto",
session_manager=session_manager,
)

📂 file_session_manager.py

Same record-based approach, backed by S3 instead of local disk:

from strands import Agent
from strands.session.s3_session_manager import S3SessionManager
session_manager = S3SessionManager(
session_id="customer-session-001",
bucket="my-agent-sessions",
prefix="customer-service/",
region_name="us-east-1",
)
agent = Agent(session_manager=session_manager)

📂 s3_session_manager.py

SnapshotSessionManager saves the session state together, instead of saving each message as a separate record.

from strands import Agent
from strands.session import SnapshotSessionManager
from strands.storage import LocalFileStorage
from customer_service_tools import lookup_customer, get_order_history, process_refund
SYSTEM_PROMPT = "Help customers with their orders using the available tools."
session_manager = SnapshotSessionManager(
session_id="customer-session-001",
storage=LocalFileStorage("./sessions"),
)
agent = Agent(
tools=[lookup_customer, get_order_history, process_refund],
system_prompt=SYSTEM_PROMPT,
context_manager="auto",
session_manager=session_manager,
)

Persistence happens automatically: agent state is saved after each invocation by default. Use save_latest_on="message" to save after every message instead.

For production, swap LocalFileStorage for S3Storage:

from strands.storage import S3Storage
session_manager = SnapshotSessionManager(
session_id="customer-session-001",
storage=S3Storage(bucket="my-agent-sessions", prefix="production/"),
)

📂 snapshot_session_manager.py

ManagerBest For
SnapshotSessionManagerSave and restore a single agent, Graph/Swarm, or Bidi session.
FileSessionManagerExisting record-based sessions; retains their storage format.
S3SessionManagerSame as File but with S3 for cross-machine access.

Session managers are one of three related pieces, and it helps to keep them straight:

  • Session manager: persists the conversation so the agent can resume where it left off. Scoped to one session.
  • Memory manager: durable knowledge that carries across sessions (user preferences, facts, decisions) without replaying old conversations. Backed by one or more memory stores.
  • Storage: the byte-level backend underneath both. LocalFileStorage, S3Storage, and community backends implement the same Storage interface, so a session manager, a memory store, and the context manager’s stash can all share one backend.

Memory is opt-in and separate from sessions. Attach a MemoryManager with a store and the agent gets recall (a tool to search what it knows) and injection (relevant memories folded into the prompt automatically):

from strands import Agent
from strands.memory import MemoryManager
from strands.vended_memory_stores.test_memory_store import TestMemoryStore
# Zero-setup store for prototyping; swap for a production store later
store = TestMemoryStore(name="customer-service")
agent = Agent(
session_manager=session_manager, # this conversation
memory_manager=MemoryManager(stores=[store]), # knowledge across conversations
)

Because sessions, memory, and offloaded context all sit on the Storage interface, one production backend can serve all of them. Strands DynamoDB Storage is an AWS-maintained backend that fits agent workloads well: serverless, single-digit-millisecond reads, native TTL so stale sessions expire themselves, and vector search on the same table for semantic memory.

Install strands-dynamodb-storage separately and provision its table. Set it once at the agent level and every subsystem that persists bytes inherits it under its own namespace:

from strands import Agent
from strands.session import SnapshotSessionManager
from strands_dynamodb_storage import DynamoDBStorage
storage = DynamoDBStorage("agent-storage", region_name="us-east-1")
agent = Agent(
tools=[lookup_customer, get_order_history, process_refund],
system_prompt=SYSTEM_PROMPT,
context_manager="auto",
storage=storage, # shared backend
session_manager=SnapshotSessionManager("customer-session-001"), # inherits storage
)

You own the table (a string pk partition key and string sk sort key is all it needs), for basic byte storage. Optional S3 offload and vector search need additional resources and permissions; see the backend’s setup instructions.

The integrations catalog lists additional session managers, memory stores, and storage backends. They implement the same interfaces, so you can swap them in without changing agent code.

IntegrationWhat It Is
Strands DynamoDB StorageStorage backend on Amazon DynamoDB, with TTL, S3 offload, and vector search
AgentCore MemorySession manager backed by Amazon Bedrock AgentCore Memory, with long-term recall
Valkey Session ManagerSession manager on Valkey (Redis-compatible) for fast distributed storage
Memory storesCommunity-built MemoryStore backends for the MemoryManager
Storage backendsCommunity-built Storage implementations