Skip to content

Instantly share code, notes, and snippets.

@alexolinux
Created August 25, 2026 08:49
Show Gist options
  • Select an option

  • Save alexolinux/6f422cef6e00834550b324925d9d93ca to your computer and use it in GitHub Desktop.

Select an option

Save alexolinux/6f422cef6e00834550b324925d9d93ca to your computer and use it in GitHub Desktop.
Ministack Guide

MiniStack


MiniStack is a free, MIT-licensed, drop-in local AWS emulator (a LocalStack alternative). It emulates 60+ AWS services (S3, SQS, DynamoDB, Lambda, IAM, STS, RDS, etc.) behind a single local endpoint, so you can develop and test AWS-based applications entirely offline, with no AWS account, API key, or telemetry.

This tutorial assumes the AWS CLI is already installed and covers:

  1. Installing MiniStack
  2. Starting and verifying MiniStack
  3. Configuring the AWS CLI so you don't need --endpoint-url on every command
  4. Environment management — reset, restart, persistence, full cleanup

1. Installing MiniStack

Choose one of the two methods below.

Option A — Install via PyPI (simplest)

pip install ministack

Start it:

ministack

By default, MiniStack listens on http://localhost:4566. To use a different port:

GATEWAY_PORT=5000 ministack

Option B — Install via Docker (recommended for management/cleanup convenience)

docker run -d --name ministack -p 4566:4566 ministackorg/ministack

With disk persistence enabled (state survives container restarts — see section 4):

docker run -d --name ministack \
  -p 4566:4566 \
  -e PERSIST_STATE=1 \
  -e STATE_DIR=/data/ministack-state \
  -v /tmp/ministack-data:/data \
  ministackorg/ministack

If you want real backing services (actual Postgres/MySQL containers for RDS, real Redis for ElastiCache, real Docker containers for ECS, etc.), mount the Docker socket:

docker run -d --name ministack \
  -p 4566:4566 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  ministackorg/ministack

Or via Docker Compose, if you cloned the repo:

git clone https://github.com/ministackorg/ministack
cd ministack
docker compose up -d

2. Verifying MiniStack Is Running

curl http://localhost:4566/_ministack/health

Healthy response:

{"services": {"...": "available"}, "status": "available"}

If you're waiting for init.d/ready.d startup scripts to finish before running anything against it, poll readiness instead:

curl -s -o /dev/null -w "%{http_code}\n" http://localhost:4566/_ministack/ready

Returns 503 while init scripts are still running, 200 once ready.


3. Configuring the AWS CLI to Use MiniStack Automatically

MiniStack doesn't validate credentials, but the AWS CLI still requires something to be configured.

Create a dedicated profile:

aws configure --profile ministack
AWS Access Key ID: test
AWS Secret Access Key: test
Default region name: us-east-1
Default output format: json

Now, to avoid passing --endpoint-url=http://localhost:4566 on every command, edit ~/.aws/config and add a services block tied to this profile:

[profile ministack]
region = us-east-1
output = json
endpoint_url = http://localhost:4566
export AWS_PROFILE=ministack
aws s3 ls
aws dynamodb list-tables
export AWS_PROFILE=ministack
aws s3 ls
aws dynamodb list-tables

No --endpoint-url needed, and other profiles pointing at real AWS stay untouched.

Quicker alternative for a throwaway shell session: export AWS_ENDPOINT_URL=http://localhost:4566 applies to every service globally, but it's less safe long-term since it isn't scoped to a specific profile.


4. Environment Management

This is the part people often miss: MiniStack keeps state in memory (and optionally on disk), and it exposes an admin HTTP surface under /_ministack/* for managing that state without tearing the whole thing down.

4.1 Reset the environment (soft reset — keep the process running)

Wipes all in-memory state across every service (buckets, queues, tables, functions, everything) but keeps the MiniStack process/container alive:

curl -X POST http://localhost:4566/_ministack/reset

Useful between test runs, or whenever your local environment has drifted and you just want a clean slate without restarting the container.

To also re-run your init.d bootstrap scripts right after the reset (e.g. to recreate baseline buckets/queues/tables automatically):

curl -X POST "http://localhost:4566/_ministack/reset?init=1"

Notes:

  • A global reset lock serializes concurrent reset calls, so no service is left in a half-reset state.
  • If PERSIST_STATE=1 is set, reset also deletes the JSON snapshots in STATE_DIR and the object bytes in S3_DATA_DIR, so a subsequent restart won't reload the old state.
  • Lambda's warm container pool is drained as part of a reset too.

4.2 Change runtime config without restarting

A small whitelist of settings can be flipped live via POST /_ministack/config, useful for switching behavior mid-session (e.g. Athena engine, Step Functions wait scaling, Lambda executor):

curl -X POST http://localhost:4566/_ministack/config \
  -H 'Content-Type: application/json' \
  -d '{"lambda_svc.LAMBDA_EXECUTOR":"docker"}'

4.3 Restart the process/container (state depends on persistence)

  • PyPI install: stop with Ctrl+C and run ministack again.
  • Docker:
    docker restart ministack

If PERSIST_STATE=1 (and S3_PERSIST for object bytes), your data survives the restart. Otherwise, a restart behaves like a full reset — everything is wiped.

4.4 Full teardown (hard reset — destroy the container and all data)

When you want to guarantee a completely clean environment, including any mounted persisted state:

docker stop ministack
docker rm -v ministack

If you're using Docker Compose:

docker compose down -v

The -v flag also removes named volumes, so any persisted state directories tied to the compose stack are wiped too.

If you mounted a host directory for persistence manually (e.g. -v /tmp/ministack-data:/data), also clear it if you want a truly clean slate:

rm -rf /tmp/ministack-data/*

4.5 Inspecting sent SES emails (useful while managing test data)

Not a reset command, but handy for environment debugging — MiniStack captures SES emails in memory instead of sending them:

curl http://localhost:4566/_ministack/ses/messages

Quick reference

Goal Command
Wipe all service state, keep container running curl -X POST http://localhost:4566/_ministack/reset
Wipe state + re-run init scripts curl -X POST "http://localhost:4566/_ministack/reset?init=1"
Change a runtime setting live curl -X POST http://localhost:4566/_ministack/config -d '{...}'
Restart process/container (persists if PERSIST_STATE=1) docker restart ministack
Full teardown, delete everything docker rm -v ministack (or docker compose down -v)
Check liveness curl http://localhost:4566/_ministack/health
Check readiness (init scripts done) curl http://localhost:4566/_ministack/ready

5. Quick End-to-End Test

aws s3 mb s3://demo-bucket
aws s3 cp ./somefile.txt s3://demo-bucket/
aws s3 ls s3://demo-bucket

curl -X POST http://localhost:4566/_ministack/reset

aws s3 ls s3://demo-bucket   # should now fail — the bucket is gone

If the last command returns a "bucket does not exist" error, the reset worked as expected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment