DynamoDB Local (docker-compose)¶
This page documents the local DynamoDB stack we use for developing the
storage layer (parrot.storage.dynamodb, parrot.storage.chat,
parrot.storage.artifacts) without hitting real AWS.
Compose file: docker-compose.dynamodb.yml
Init script: scripts/init_dynamodb_local.py
What you get¶
Two containers, one named volume:
| Service | Image | Port | Purpose |
|---|---|---|---|
dynamodb-local |
amazon/dynamodb-local:latest |
8000 | The DynamoDB engine |
dynamodb-admin |
aaronshaf/dynamodb-admin:latest |
8001 | Web UI to browse tables / items |
Persistence: the dynamodb-local-data named volume — data survives
docker compose down but is wiped by docker compose down -v.
The dynamodb-local container runs with -sharedDb, so every client
sees the same database file regardless of the access-key / region it
presents. This matches the "one developer, one laptop" use case — no
accidental partitioning by credentials.
First-time setup¶
# 1. Bring the stack up
docker compose -f docker-compose.dynamodb.yml up -d
# 2. Activate the venv (required by project rules)
source .venv/bin/activate
# 3. Create the parrot-conversations and parrot-artifacts tables,
# plus enable the "ttl" TTL attribute on both.
python scripts/init_dynamodb_local.py
After step 3 you can open the admin UI at http://localhost:8001 and see two empty tables.
Configuration (env/.env)¶
A dedicated [dynamodb] section is appended to env/.env:
[dynamodb]
DYNAMODB_ENDPOINT_URL=http://localhost:8000
DYNAMODB_REGION=us-east-1
DYNAMODB_CONVERSATIONS_TABLE=parrot-conversations
DYNAMODB_ARTIFACTS_TABLE=parrot-artifacts
These map 1-to-1 onto the variables read in
packages/ai-parrot/src/parrot/conf.py:
DYNAMODB_ENDPOINT_URL— when set,parrot.storage.chatpasses it through toaioboto3.resource("dynamodb", endpoint_url=...), pointing the client at the container instead of AWS.DYNAMODB_REGION— any valid AWS region string; DynamoDB Local does not enforce it, butboto3requires one.DYNAMODB_CONVERSATIONS_TABLE/DYNAMODB_ARTIFACTS_TABLE— table names used byConversationDynamoDB.
Credentials¶
ConversationDynamoDB takes its credentials from AWS_ACCESS_KEY /
AWS_SECRET_KEY in conf.py, which fall back to the existing
AWS_KEY / AWS_SECRET variables in env/.env. No new keys are
required — DynamoDB Local accepts any non-empty credential pair,
and with -sharedDb it ignores the access key for partitioning
anyway. The existing prod-looking AWS keys in env/.env work fine.
To use real AWS DynamoDB again, comment out DYNAMODB_ENDPOINT_URL
(or delete the line): conf.py defaults it to None, which makes
aioboto3 go to the real regional endpoint.
Day-to-day commands¶
# Start / stop / tail logs
docker compose -f docker-compose.dynamodb.yml up -d
docker compose -f docker-compose.dynamodb.yml down
docker compose -f docker-compose.dynamodb.yml logs -f dynamodb-local
# Wipe ALL local data (drops the named volume)
docker compose -f docker-compose.dynamodb.yml down -v
# One-shot CLI check against the running container
aws dynamodb list-tables \
--endpoint-url http://localhost:8000 \
--region us-east-1
Table schema (what the init script creates)¶
Both tables share the same composite key design, matching the
_build_pk / _build_sk helpers in
packages/ai-parrot/src/parrot/storage/dynamodb.py:
| Attribute | Type | Role |
|---|---|---|
PK |
String | Partition key — USER#<user_id>#AGENT#<agent_id> |
SK |
String | Sort key — THREAD#<session_id> / ...#TURN#<id> |
ttl |
Number | TTL epoch seconds (180-day default) |
Billing mode is PAY_PER_REQUEST. TTL is enabled on the ttl
attribute so expired rows disappear automatically (real AWS only —
DynamoDB Local registers the setting but does not actively expire).
Troubleshooting¶
Connection refused from Python. Make sure the container is up
(docker ps | grep parrot-dynamodb-local) and that
DYNAMODB_ENDPOINT_URL is http://localhost:8000, not 127.0.0.1
inside another container.
ResourceNotFoundException: Cannot do operations on a non-existent
table. You skipped python scripts/init_dynamodb_local.py.
Port 8000 already in use. Something else owns the port. Edit the
ports: block in docker-compose.dynamodb.yml (e.g. "8010:8000")
and update DYNAMODB_ENDPOINT_URL to match.
I want a clean slate. docker compose -f
docker-compose.dynamodb.yml down -v && docker compose -f
docker-compose.dynamodb.yml up -d && python
scripts/init_dynamodb_local.py.