AWS SAM
DynamoDB
Docker
Serverless
Cloud Development

connecting AWS SAM Local with dynamodb in docker

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Running AWS SAM locally against DynamoDB in Docker is a practical way to test Lambda behavior before deployment. When this setup fails, the problem is usually container networking or endpoint configuration rather than DynamoDB itself. A reliable local workflow uses one shared Docker network, an explicit endpoint for local mode, and a repeatable table bootstrap step.

Put Both Containers on the Same Docker Network

Your Lambda containers run inside Docker when you use sam local. That means localhost inside the function container does not refer to the DynamoDB container. The safer setup is to create a named Docker network and attach both services to it.

bash
1docker network create sam-local-net
2
3docker run -d \
4  --name dynamodb-local \
5  --network sam-local-net \
6  -p 8000:8000 \
7  amazon/dynamodb-local

The container name dynamodb-local now becomes the hostname other containers on that network can resolve.

Start SAM on the Same Network

AWS SAM has a --docker-network option for local commands. Use it when starting the local API or function runtime so the Lambda container joins the same network as DynamoDB.

bash
sam build
sam local start-api --docker-network sam-local-net

Without that option, the Lambda container may only join Docker's default bridge network and fail to reach dynamodb-local.

Pass a Local Endpoint into the Function

Your Lambda code should know when it is running locally and override the DynamoDB endpoint only in that case.

yaml
1Resources:
2  OrdersFunction:
3    Type: AWS::Serverless::Function
4    Properties:
5      Handler: app.handler
6      Runtime: python3.12
7      Environment:
8        Variables:
9          APP_ENV: local
10          DDB_ENDPOINT: http://dynamodb-local:8000
11          TABLE_NAME: orders

That keeps local and deployed behavior separate. In AWS, you normally do not set a custom endpoint for DynamoDB.

Connect from Lambda Code

For local DynamoDB, dummy credentials are fine, but you should still set region and endpoint explicitly.

python
1import os
2import boto3
3
4
5def get_table():
6    endpoint = None
7    if os.getenv("APP_ENV") == "local":
8        endpoint = os.getenv("DDB_ENDPOINT")
9
10    dynamodb = boto3.resource(
11        "dynamodb",
12        endpoint_url=endpoint,
13        region_name="us-east-1",
14        aws_access_key_id="dummy",
15        aws_secret_access_key="dummy",
16    )
17    return dynamodb.Table(os.getenv("TABLE_NAME", "orders"))
18
19
20def handler(event, context):
21    table = get_table()
22    order_id = event.get("id", "1")
23
24    table.put_item(Item={"id": order_id, "status": "created"})
25    return {"statusCode": 200, "body": "ok"}

The important part is that the endpoint hostname matches the Docker container name on the shared network.

Create the Table Before Testing

Local Lambda code can connect successfully and still fail because the table does not exist. Bootstrap the table before running integration tests.

bash
1aws dynamodb create-table \
2  --endpoint-url http://localhost:8000 \
3  --table-name orders \
4  --attribute-definitions AttributeName=id,AttributeType=S \
5  --key-schema AttributeName=id,KeyType=HASH \
6  --billing-mode PAY_PER_REQUEST

Once the table exists, you can verify the whole request path from API call to stored item.

bash
1curl -s -X POST http://127.0.0.1:3000/orders -d '{"id":"42"}'
2
3aws dynamodb get-item \
4  --endpoint-url http://localhost:8000 \
5  --table-name orders \
6  --key '{"id":{"S":"42"}}'

Keep Local and Cloud Configuration Separate

Do not hardcode local endpoints into shared application logic. Use an explicit environment flag or local configuration source so deployed code keeps using the managed AWS endpoint.

This separation matters because local emulators are a development convenience, not a production dependency. If the same config path is reused everywhere, it becomes too easy to leak local values into a deployed environment.

Common Pitfalls

The biggest pitfall is using localhost:8000 inside Lambda code. From within the Lambda container, that refers to the container itself, not the DynamoDB container.

Another common issue is starting DynamoDB on one Docker network and SAM on another. The containers may both be healthy and still be unable to see each other.

Teams also often skip table creation and then misread a ResourceNotFoundException as a networking problem.

Finally, avoid letting local endpoint overrides remain active in deployed stacks. Keep the local path deliberate and isolated.

Summary

  • Put DynamoDB Local and SAM Lambda containers on the same named Docker network.
  • Start SAM with --docker-network so Lambda can resolve the DynamoDB container name.
  • Pass a local DynamoDB endpoint only in local mode.
  • Bootstrap tables before testing the integration path.
  • Keep emulator configuration separate from deployed AWS settings.

Course illustration
Course illustration

All Rights Reserved.