DEV Community

Cover image for A Technical Introduction to LocalStack
Ernesto Herrera Salinas
Ernesto Herrera Salinas

Posted on

A Technical Introduction to LocalStack

LocalStack is an excellent tool that allows you to emulate AWS services on your local machine. By spinning up a local environment that replicates various AWS services, developers can speed up their development and testing cycles without incurring cloud costs or requiring an active AWS account. In this post, we’ll discuss what LocalStack is, how to install it, and how you can use it with various AWS services in your local development workflow.


What is LocalStack?

LocalStack is a fully functional local AWS cloud stack. It provides mock implementations of many popular AWS services, including S3, DynamoDB, Lambda, and more. Using LocalStack, you can:

  • Simulate AWS services locally for development and testing.
  • Avoid AWS billing charges for creating and destroying resources repeatedly.
  • Speed up the development cycle by removing the dependency on external AWS infrastructure.
  • Test AWS infrastructure and application logic in a controlled environment.

LocalStack is built using Python, Docker, and various mocks and emulators for the different AWS services. Once you have LocalStack running, you can use your existing AWS CLI or SDK commands, provided you point them to your local endpoints.


Installation

Prerequisites

  1. Docker: LocalStack uses Docker containers to spin up AWS mock services. Make sure you have Docker installed and running.
  2. Python 3+ (if you prefer to install the LocalStack CLI via pip).

Installing LocalStack

The recommended way to run LocalStack is by using Docker Compose. You can either:

Below is an example docker-compose.yml configuration:

version: "3.8"
services:
  localstack:
    image: localstack/localstack:latest
    container_name: localstack
    ports:
      - "4566:4566"   # LocalStack edge port
      - "4571:4571"
    environment:
      - SERVICES=s3,dynamodb,lambda   # Which services to start
      - DEBUG=1
      - DATA_DIR=/tmp/localstack/data
      - LAMBDA_EXECUTOR=docker
      - HOST_TMP_FOLDER=/tmp/localstack
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
      - "./localstack-data:/tmp/localstack"
Enter fullscreen mode Exit fullscreen mode

Note: LocalStack exposes port 4566 (the “edge” port) to accept requests for all services. This can simplify your endpoint configurations.

After saving this file, run:

docker-compose up
Enter fullscreen mode Exit fullscreen mode

LocalStack will now start in your terminal, showing logs about each service being initialized.


Using LocalStack

Once LocalStack is running, you can interact with it using:

  1. AWS CLI (by configuring endpoints)
  2. AWS SDKs (e.g., boto3 in Python)
  3. LocalStack CLI (optional, if installed locally)

Configuring the AWS CLI

To interact with LocalStack using the AWS CLI, you need to specify the LocalStack endpoint and credentials. For example:

aws configure set aws_access_key_id test
aws configure set aws_secret_access_key test
aws configure set default.region us-east-1
Enter fullscreen mode Exit fullscreen mode

Then, you can specify the --endpoint-url for each service call. For instance, to create an S3 bucket:

aws s3api create-bucket \
    --bucket local-bucket \
    --endpoint-url http://localhost:4566
Enter fullscreen mode Exit fullscreen mode

To list S3 buckets:

aws s3api list-buckets \
    --endpoint-url http://localhost:4566
Enter fullscreen mode Exit fullscreen mode

You should see your locally created buckets in the output.


Using LocalStack with boto3 (Python)

Below is a short Python snippet showing how to connect to LocalStack’s S3 service using boto3.

import boto3

# Create an S3 client pointing to LocalStack
s3 = boto3.client(
    's3',
    endpoint_url='http://localhost:4566',
    aws_access_key_id='test',
    aws_secret_access_key='test',
    region_name='us-east-1'
)

# Create a bucket
bucket_name = 'local-bucket'
s3.create_bucket(Bucket=bucket_name)

# List buckets
response = s3.list_buckets()
print("Buckets:")
for bucket in response['Buckets']:
    print(f"  - {bucket['Name']}")

# Upload a file
file_content = b"Hello from LocalStack!"
s3.put_object(Bucket=bucket_name, Key='hello.txt', Body=file_content)

# Download the file
res = s3.get_object(Bucket=bucket_name, Key='hello.txt')
downloaded_content = res['Body'].read()
print("Downloaded file content:", downloaded_content.decode('utf-8'))
Enter fullscreen mode Exit fullscreen mode

Running this script will interact with your local S3 service hosted by LocalStack.


Example: DynamoDB

Let’s create a DynamoDB table and add a few items to it:

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

Now, list all tables:

aws dynamodb list-tables \
    --endpoint-url http://localhost:4566
Enter fullscreen mode Exit fullscreen mode

And insert data:

aws dynamodb put-item \
    --table-name MyLocalTable \
    --item '{"Id": {"S": "1001"}, "Name": {"S": "Test Item"}}' \
    --endpoint-url http://localhost:4566
Enter fullscreen mode Exit fullscreen mode

Finally, query to see your data:

aws dynamodb scan \
    --table-name MyLocalTable \
    --endpoint-url http://localhost:4566
Enter fullscreen mode Exit fullscreen mode

Example: Lambda

To test Lambda functions locally, you can:

  1. Use SAM CLI to build and deploy your Lambda code into LocalStack.
  2. Or directly create your Lambda function using a zip package and uploading via AWS CLI.

Creating a zip for a simple Python function:

# main.py
def handler(event, context):
    return {
        "statusCode": 200,
        "body": "Hello from LocalStack!"
    }

# Zip the file
zip function.zip main.py
Enter fullscreen mode Exit fullscreen mode

Create the Lambda function in LocalStack:

aws lambda create-function \
    --function-name LocalLambda \
    --handler main.handler \
    --runtime python3.9 \
    --zip-file fileb://function.zip \
    --role arn:aws:iam::123456:role/irrelevant \
    --endpoint-url http://localhost:4566
Enter fullscreen mode Exit fullscreen mode

Test the function:

aws lambda invoke \
    --function-name LocalLambda \
    --payload '{}' \
    --endpoint-url http://localhost:4566 \
    output.json
Enter fullscreen mode Exit fullscreen mode

Check the results in output.json:

cat output.json
# {
#    "statusCode": 200,
#    "body": "Hello from LocalStack!"
# }
Enter fullscreen mode Exit fullscreen mode

Tips and Best Practices

  1. Service-Specific Ports vs. Edge Port: By default, all AWS services in LocalStack are available through the edge port (4566). If you need to, you can enable service-specific ports (e.g., 4572 for S3). However, it’s recommended to stick to the edge port for simplicity.
  2. Persisting Data: By default, LocalStack does not persist data across restarts. To persist data, set the DATA_DIR environment variable or mount a volume in Docker (as in the example docker-compose.yml).
  3. Integration Testing: LocalStack can be used for end-to-end integration tests without deploying to AWS. You can run your CI/CD workflows using LocalStack in Docker containers and test your infrastructure changes reliably.
  4. Upgrading: LocalStack is actively developed, so new features and bug fixes are frequently released. Keep your Docker image updated to take advantage of the latest changes.

Conclusion

LocalStack is a powerful tool that brings AWS infrastructure right to your local machine. Whether you’re developing new services, testing your IaC (Infrastructure as Code) templates, or running integration tests, LocalStack provides a quick, cost-effective, and convenient solution.

By following the examples above, you’ll be able to spin up essential AWS services like S3, DynamoDB, and Lambda in your local environment. This approach not only accelerates your development cycle but also ensures that you can verify your application logic thoroughly before deploying to real AWS infrastructure.

Give it a try and see how it transforms your local AWS development experience!


References:



Enter fullscreen mode Exit fullscreen mode

Top comments (0)