DEV Community

Cover image for Learning AWS Without an AWS Account: Running S3, DynamoDB, and Lambda Locally
Micheal Angelo
Micheal Angelo

Posted on

Learning AWS Without an AWS Account: Running S3, DynamoDB, and Lambda Locally

Learning AWS Without an AWS Account: Running S3, DynamoDB, and Lambda Locally

Image: Local AWS architecture using Floci, Docker, and AWS CLI.

For a long time, I approached AWS the same way many beginners do.

I would read documentation, watch tutorials, and try to memorize services.

The problem was simple:

Reading about cloud services is very different from actually using them.

At the same time, I didn't want to create resources in a cloud account while learning basic concepts.

So I started looking for a way to experiment locally.

That's how I came across Floci, an open-source AWS emulator that exposes AWS-compatible APIs on a local machine.

The idea is surprisingly simple:

Instead of sending requests to AWS, send them to a local container that behaves like AWS.


Why Learn AWS Locally?

When learning cloud concepts, most beginners want to answer questions like:

  • What is S3 really used for?
  • How does DynamoDB store data?
  • What does Lambda actually execute?
  • What role does AWS CLI play?

These questions are easier to answer by creating resources than by reading definitions.

Local emulation makes that possible without worrying about cloud costs.


High-Level Architecture

The setup looked like this:

AWS CLI
    ↓
localhost:4566
    ↓
Floci Container
    ├── S3 Emulator
    ├── DynamoDB Emulator
    └── Lambda Emulator
Enter fullscreen mode Exit fullscreen mode

Instead of communicating with AWS infrastructure, AWS CLI communicates with Floci running on the local machine.


Running Floci with Docker

The first step was starting the emulator.

A simple Docker Compose configuration was enough:

services:
  floci:
    image: floci/floci:latest
    ports:
      - "4566:4566"
Enter fullscreen mode Exit fullscreen mode

Then:

docker compose up -d
Enter fullscreen mode Exit fullscreen mode

Port 4566 became the endpoint through which AWS CLI communicated with Floci.


Understanding AWS CLI

AWS CLI stands for:

Amazon Web Services Command Line Interface

It acts as a client that converts commands into AWS API requests.

For example:

aws s3 ls
Enter fullscreen mode Exit fullscreen mode

can be viewed conceptually as:

AWS CLI
     ↓
AWS API Request
     ↓
S3 Service
Enter fullscreen mode Exit fullscreen mode

Normally those requests go to AWS.

With Floci, the destination changes:

--endpoint-url=http://localhost:4566
Enter fullscreen mode Exit fullscreen mode

This tells AWS CLI to communicate with the local emulator instead.


Learning S3

What Is S3?

S3 is an object storage service.

A useful mental model is:

Bucket
 ├── resume.pdf
 ├── image.png
 └── hello.txt
Enter fullscreen mode Exit fullscreen mode

A bucket acts as a container.

Everything stored inside it is called an object.


Creating a Bucket

aws --endpoint-url=http://localhost:4566 \
s3 mb s3://notes-app-bucket
Enter fullscreen mode Exit fullscreen mode

Uploading a File

echo "Hello from AWS Learning" > hello.txt
Enter fullscreen mode Exit fullscreen mode
aws --endpoint-url=http://localhost:4566 \
s3 cp hello.txt s3://notes-app-bucket/
Enter fullscreen mode Exit fullscreen mode

Listing Objects

aws --endpoint-url=http://localhost:4566 \
s3 ls s3://notes-app-bucket
Enter fullscreen mode Exit fullscreen mode

Downloading an Object

aws --endpoint-url=http://localhost:4566 \
s3 cp s3://notes-app-bucket/hello.txt .
Enter fullscreen mode Exit fullscreen mode

Key Insight

S3 stores:

  • Images
  • Videos
  • Documents
  • Backups
  • Application assets

S3 is not a database.

It is object storage.


Learning DynamoDB

What Is DynamoDB?

DynamoDB is a NoSQL database service.

Instead of storing files, it stores records.

Example:

{
  "noteId": "1",
  "title": "Learning AWS",
  "content": "Today I learned S3"
}
Enter fullscreen mode Exit fullscreen mode


Creating a Table

aws --endpoint-url=http://localhost:4566 \
dynamodb create-table \
--table-name Notes \
--attribute-definitions \
AttributeName=noteId,AttributeType=S \
--key-schema \
AttributeName=noteId,KeyType=HASH \
--billing-mode PAY_PER_REQUEST
Enter fullscreen mode Exit fullscreen mode

Inserting Data

aws --endpoint-url=http://localhost:4566 \
dynamodb put-item \
--table-name Notes \
--item '{
  "noteId":{"S":"1"},
  "title":{"S":"Learning AWS"},
  "content":{"S":"Today I learned S3 and DynamoDB"}
}'
Enter fullscreen mode Exit fullscreen mode

Retrieving Data

aws --endpoint-url=http://localhost:4566 \
dynamodb get-item \
--table-name Notes \
--key '{"noteId":{"S":"1"}}'
Enter fullscreen mode Exit fullscreen mode

Key Insight

A useful distinction is:

S3
 ↓
Stores Files
Enter fullscreen mode Exit fullscreen mode

versus

DynamoDB
 ↓
Stores Records
Enter fullscreen mode Exit fullscreen mode

Understanding this difference made both services much easier to reason about.


Learning Lambda

What Is Lambda?

Lambda is a serverless compute service.

Unlike S3 or DynamoDB, Lambda does not primarily store data.

Its job is to execute code.

Example:

def lambda_handler(event, context):
    return {
        "statusCode": 200,
        "body": "Hello from Lambda"
    }
Enter fullscreen mode Exit fullscreen mode

[Insert Figure 4: Lambda Execution Flow Here]


Packaging the Function

Lambda expects a deployment artifact.

The simplest option is a ZIP file.

zip function.zip handler.py
Enter fullscreen mode Exit fullscreen mode

The ZIP package contains:

  • Application code
  • Supporting files
  • Dependencies

Creating the Function

aws --endpoint-url=http://localhost:4566 \
lambda create-function \
--function-name HelloLambda \
--runtime python3.11 \
--handler handler.lambda_handler \
--zip-file fileb://function.zip \
--role arn:aws:iam::000000000000:role/lambda-role
Enter fullscreen mode Exit fullscreen mode

The First Failure

The first invocation failed with:

Failed to start Lambda container
Enter fullscreen mode Exit fullscreen mode

This turned out to be a Docker issue.

Lambda execution inside Floci relies on runtime containers.

Floci needed access to Docker itself.


Fixing the Issue

The solution was mounting Docker's socket:

services:
  floci:
    image: floci/floci:latest
    ports:
      - "4566:4566"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
Enter fullscreen mode Exit fullscreen mode

Once Floci could communicate with Docker, Lambda executed successfully.


Invoking Lambda

aws --endpoint-url=http://localhost:4566 \
lambda invoke \
--function-name HelloLambda \
response.json
Enter fullscreen mode Exit fullscreen mode

Result:

{
  "statusCode": 200,
  "body": "Hello from Lambda"
}
Enter fullscreen mode Exit fullscreen mode

A Brief Note on IAM

One interesting observation was that Lambda creation succeeded even though no real IAM role was created.

The emulator is intentionally more forgiving than AWS.

In real AWS, IAM is responsible for controlling:

  • Who can access resources
  • Which actions are allowed
  • Which services can communicate

A Lambda execution role acts as the identity under which the function runs.

Even simple functions require one because AWS needs to know what permissions the function should have if it later interacts with services such as S3 or DynamoDB.


What This Exercise Taught Me

By the end of the experiment, the following concepts became much clearer:

S3

  • Creating buckets
  • Uploading objects
  • Downloading objects
  • Listing objects

DynamoDB

  • Creating tables
  • Inserting records
  • Querying records
  • Understanding primary keys

Lambda

  • Packaging code
  • Deploying functions
  • Executing code
  • Troubleshooting runtime issues

Infrastructure Concepts

  • Docker containers
  • Service emulation
  • Runtime environments
  • Deployment artifacts
  • IAM fundamentals

Final Mental Model

When I started, S3, DynamoDB, and Lambda felt like unrelated AWS services.

After running them locally, a much simpler mental model emerged:

AWS CLI
     ↓
Floci
     ├── S3       → Stores Files
     ├── DynamoDB → Stores Records
     └── Lambda   → Runs Code
Enter fullscreen mode Exit fullscreen mode

Sometimes the fastest way to understand cloud services isn't reading more documentation.

It's building a small environment, creating resources, breaking things, fixing them, and observing how the pieces fit together.

Top comments (0)