LocalStack and MiniStack — Emulating AWS Locally
LocalStack and MiniStack — Emulating AWS Locally
Most of AWS lives in magical data centers across the internet, charging money to do work. To verify on a developer machine, three costs apply daily: (1) creating a PoC account on real AWS, (2) paying somewhere, (3) stalling whenever the internet goes down. Local emulators bring all three close to zero.
1. About LocalStack
LocalStack is the oldest and most battle-tested AWS emulator (since 2017). LocalStack LLC (Berlin · Mountain View) operates it, with Community (free, Apache 2.0) and Pro (paid) editions.
Included in Community:
- S3 · SQS · SNS · DynamoDB · Lambda · KMS · EventBridge · SES.
Added in Pro:
- IAM policy simulation.
- Almost all CloudFormation resources.
- EKS.
The default gateway port is 4566 (the edge port).
2. About MiniStack
MiniStack appeared in 2025 as a free alternative to LocalStack. MIT licensed, with 45+ AWS services in a single container. Its biggest distinction is "don't fake — run the real thing":
- An RDS call brings up a real Postgres container.
- ElastiCache becomes real Redis.
- ECS becomes real Docker containers.
The image is around 270 MB with idle memory near 21 MB, and startup is about 2 seconds. Gateway port is also 4566 (LocalStack-compatible).
3. How they differ
| Item | LocalStack Community | MiniStack |
|---|---|---|
| License | Apache 2.0 | MIT |
| Image size | ~2.5 GB | ~270 MB |
| Idle memory | ~500 MB | ~21 MB |
| Startup time | 30~60 s | < 2 s |
| Core behavior | Mock all services | Run real containers for infra services |
| Service coverage | S3 · SQS · SNS · DynamoDB · Lambda · SES · KMS · EventBridge | 45+ — RDS · ElastiCache · ECS · EKS · S3 · Lambda · SES |
| Pro edition | Yes | No |
| Korean references | Many | Few (newer) |
When LocalStack fits — Lambda invoke simulation, SES mail routing mock, KMS key policies, EventBridge rules, CloudFormation verification — when mock fidelity matters more.
When MiniStack fits — Verifying real connectivity to RDS · ElastiCache · ECS locally, memory-constrained laptops, drop-in LocalStack compatibility with simpler licensing.
Running both at once — A normal pattern. Use MiniStack for infrastructure verification and LocalStack for services where mock stability matters.
4. Bring up LocalStack
# docker-compose.yml
services:
localstack:
image: localstack/localstack:3.8
ports:
- "4566:4566"
environment:
SERVICES: s3,ses,sqs,sns,dynamodb,lambda,kms,iam,sts
PERSISTENCE: 1
DOCKER_HOST: unix:///var/run/docker.sock
volumes:
- ./data:/var/lib/localstack
- /var/run/docker.sock:/var/run/docker.sock
Setting SERVICES to only the active set speeds up boot. With PERSISTENCE=1, resources survive shutdowns. Services that spin up other containers (Lambda · ECS) require mounting the host docker socket.
5. Bring up MiniStack
services:
ministack:
image: ministackorg/ministack:latest
ports:
- "4566:4566"
environment:
GATEWAY_PORT: 4566
S3_PERSIST: 1
REDIS_HOST: redis
volumes:
- ./data:/tmp/ministack-data
- /var/run/docker.sock:/var/run/docker.sock
depends_on:
redis:
condition: service_healthy
redis:
image: redis:7-alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
Because MiniStack's ElastiCache is "real," a companion Redis is required. RDS spins up its own Postgres container as soon as a call arrives.
6. Calling them
For both emulators, pointing the endpoint at 4566 makes the standard AWS SDKs work out of the box. Keys can be any string (test is the convention).
import boto3
s3 = boto3.client(
"s3",
endpoint_url="http://localhost:4566",
region_name="ap-northeast-2",
aws_access_key_id="test",
aws_secret_access_key="test",
)
s3.create_bucket(Bucket="my-bucket")
s3.put_object(Bucket="my-bucket", Key="hello.txt", Body=b"world")
const s3 = new S3Client({
endpoint: "http://localhost:4566",
region: "ap-northeast-2",
credentials: { accessKeyId: "test", secretAccessKey: "test" },
forcePathStyle: true,
});
export AWS_ENDPOINT_URL=http://localhost:4566
export AWS_ACCESS_KEY_ID=test
export AWS_SECRET_ACCESS_KEY=test
aws s3 ls
The LocalStack container ships an awslocal wrapper that lets you skip the endpoint flag.
7. Running side by side — port collision
Both default to 4566, so to run them on the same machine, shift one host port. Keep the container's internal port intact to preserve SDK compatibility.
# Shift LocalStack to 4666
ports:
- "4666:4566"
ministack = boto3.client("s3", endpoint_url="http://localhost:4566", ...)
localstack = boto3.client("ses", endpoint_url="http://localhost:4666", ...)
8. Limitations
Behavior is not 1:1 with AWS — IAM permission evaluation, role assume, KMS key policy show subtle differences. Verify on real AWS at least once before going to production.
Pricing models cannot be emulated — no S3 Glacier restore time, no Lambda cold-start cost models.
Version drift — LocalStack adds new services often; MiniStack is newer with frequent version churn. Don't shape production code around emulator behavior — depend only on the endpoint.
When running in CI, after starting the container, poll _localstack/health or _ministack/health until ready. A bare up -d followed by an immediate call returns 503.
Closing thoughts
Local emulators reduce the cost of cloud learning and development to nearly zero. LocalStack for mock fidelity, MiniStack for real infra behavior — running both is the most solid shape. The principle that production verification needs at least one real-AWS pass remains.
Next
- supabase-self-hosted
- firebase-emulator
LocalStack · LocalStack GitHub · MiniStack · boto3 · @aws-sdk/client-s3 · awslocal for reference.