Configuration
All MiniStack configuration is driven by environment variables and a small admin HTTP surface. This page is the consolidated reference.
ministack/app.py, ministack/core/*, and per-service modules). Search os.environ / os.getenv in the repo to find the authoritative site where each is read.
General
| Variable | Default | Purpose |
|---|---|---|
GATEWAY_PORT | 4566 | Port the single ASGI gateway listens on. Fallback order: GATEWAY_PORT → EDGE_PORT → 4566. |
EDGE_PORT | (fallback) | Legacy alias honored when GATEWAY_PORT is unset. |
MINISTACK_HOST | localhost | Hostname the server advertises (used in returned endpoints). |
MINISTACK_REGION | us-east-1 | Default AWS region for callers who don't sign requests with SigV4. |
LOG_LEVEL | INFO | DEBUG, INFO, WARNING, ERROR. DEBUG logs every request's routing decision. |
MINISTACK_WORKER_THREADS | 64 | Size of the thread pool executor used for sync-in-async offload and Lambda local runs. |
SERVICES | (all enabled) | Comma-separated filter, e.g. s3,sqs,lambda. Only those services answer — good for shrinking startup in tiny test matrices. |
Persistence
Three independent layers. Enable whatever subset fits your workflow.
| Variable | Default | Purpose |
|---|---|---|
PERSIST_STATE / LOCALSTACK_PERSISTENCE | 0 | Master switch. When 1, every multi-tenant service snapshots its in-memory maps to STATE_DIR on shutdown and restores on startup. |
STATE_DIR | /tmp/ministack-state | Directory for JSON snapshots. Mount to a host volume in Docker to survive container recreation. |
S3_PERSIST | 0 (auto-enabled if LOCALSTACK_PERSISTENCE=1) | Writes S3 object bytes (the body, not just metadata) to disk. |
S3_DATA_DIR | /tmp/ministack-data/s3 | Where S3 object files are stored. Mount this for persistent object storage. |
RDS_PERSIST | 0 | Switches RDS Docker containers from tmpfs to Docker named volumes. Real databases, real persistence. |
RDS_TMPFS_SIZE | 256m | Size of the tmpfs mount when RDS_PERSIST=0. Bump to 1g or 2g if tests hit "no space left on device". |
Nested containers (RDS / EKS / ElastiCache / Lambda)
Services that spawn real sidecar containers share a common networking + registry-prefix surface.
| Variable | Default | Purpose |
|---|---|---|
DOCKER_NETWORK | (unset) | Attaches every container-backed service to the named Docker network. RDS/ElastiCache endpoints return the routable in-network IP instead of localhost. |
LAMBDA_DOCKER_NETWORK | (falls back to DOCKER_NETWORK) | Lambda-scoped override. Legacy — prefer DOCKER_NETWORK. |
MINISTACK_IMAGE_PREFIX | (unset) | Private-registry prefix prepended to every nested image (postgres, mysql, mariadb, redis, memcached, k3s, Lambda runtimes under public.ecr.aws/lambda/*). Idempotent on already-prefixed images. The Testcontainers Java module auto-forwards hub.image.name.prefix into this variable. |
RDS_BASE_PORT | 15432 | First host port allocated to an RDS container. Each subsequent DB gets the next free port. |
ELASTICACHE_BASE_PORT | 16379 | First host port for ElastiCache containers. |
EKS_BASE_PORT | 16443 | First host port for EKS k3s clusters. |
EKS_K3S_IMAGE | rancher/k3s:v1.31.4-k3s1 | k3s image tag for EKS cluster sidecars. Pin this if you need a specific Kubernetes version. |
ECS_REAP_INTERVAL_SECONDS | 60 | Interval for the ECS task reaper. Cleans up stopped task containers. |
Lambda
| Variable | Default | Purpose |
|---|---|---|
LAMBDA_EXECUTOR | local | local runs Python as a subprocess (fast, no Docker). docker uses an isolated container per invocation. docker-reuse keeps warm containers in a pool. Image-based and provided.* runtimes always use Docker regardless. |
LAMBDA_STRICT | 0 | 1 forces AWS-fidelity mode — in-process fallback is disabled and missing Docker surfaces as Runtime.DockerUnavailable. |
LAMBDA_DOCKER_FLAGS | (unset) | Extra docker run flags. Whitelisted: -e, -v, --dns, --network, --cap-add, -m, --shm-size, --tmpfs, --add-host, --privileged, --read-only. |
LAMBDA_REMOTE_DOCKER_VOLUME_MOUNT | (unset) | Path remapping for remote Docker daemons (when the daemon can't see the host's /tmp). |
LAMBDA_WARM_TTL_SECONDS | ~900 (15 min) | Idle container TTL in the warm pool. Raise for long local-dev sessions, lower for CI. |
LAMBDA_ACCOUNT_CONCURRENCY | 0 | Account-level concurrent-invocation cap. 0 = unbounded; set 1000 to simulate AWS's default. |
LAMBDA_STATE_TRANSITION_SECONDS | 0.5 | Artificial delay between Pending→Active and Active→Inactive. Matches AWS's eventual-consistency window for tests that assert on state. |
LAMBDA_ASYNC_RETRY_BASE_SECONDS | 1 | Base backoff for async invoke retries. |
LAMBDA_ASYNC_RETRY_MAX_SECONDS | 30 | Cap on async retry backoff. |
_LAMBDA_LAYERS_DIRS | (unset) | Colon-separated directories scanned for layers. Useful for local-dev layer prototyping. |
Databases & analytics
| Variable | Default | Purpose |
|---|---|---|
ATHENA_ENGINE | auto | auto uses DuckDB when installed and falls back to mock. duckdb requires DuckDB (errors if missing). mock always returns empty result sets. |
ATHENA_DATA_DIR | (derived from S3_DATA_DIR) | DuckDB working directory for Athena query staging. |
SFN_MOCK_CONFIG | (unset) | Path to a JSON mock file (AWS SFN Local format) for Step Functions Task states. |
Other services
| Variable | Default | Purpose |
|---|---|---|
SMTP_HOST | (unset) | If set (e.g. mailhog:1025), SES SendEmail/SendRawEmail forwards to a real SMTP server. Otherwise mails are stored in memory and inspectable at /_ministack/ses/messages. |
REDIS_HOST / REDIS_PORT | redis / 6379 | External Redis (if you don't want ElastiCache to spin up a container per cluster). |
Admin endpoints
All admin endpoints live under /_ministack/*. Most are also exposed under /_localstack/* for LocalStack compatibility.
| Endpoint | Method | Purpose |
|---|---|---|
/_ministack/health | GET | Liveness — returns 200 with a JSON map of service availability and init/ready script status. |
/_ministack/ready | GET | Readiness — 200 when ready.d scripts have finished, 503 while still running. |
/_ministack/reset | POST | Wipes all in-memory service state. Add ?init=1 to re-run init.d scripts. Acquires a global reset lock so concurrent requests serialize. |
/_ministack/config | POST | Runtime config for a whitelist of keys (e.g. athena.engine, stepfunctions.*, lambda_svc.*). JSON body {"key":"value"}. |
/_ministack/ses/messages | GET | Inspect sent emails. ?account=123456789012 filters by account. |
/_ministack/lambda-code/{function_name} | GET | Downloads the function's deployment ZIP. |
/_ministack/lambda-layers/{layer_name}/{version}/content | GET | Downloads a layer version ZIP. |
Init & ready scripts
On startup MiniStack runs executable files from (in order):
/docker-entrypoint-initaws.d/(LocalStack-compat) or/etc/localstack/init/boot.d/— ran synchronously before the server accepts traffic./docker-entrypoint-initaws.d/ready.d/or/etc/localstack/init/ready.d/— ran asynchronously after startup;/_ministack/readyflips to 200 once these finish.
Scripts see the usual AWS env (AWS_ACCESS_KEY_ID=test, AWS_SECRET_ACCESS_KEY=test, AWS_DEFAULT_REGION=us-east-1, AWS_ENDPOINT_URL=http://localhost:4566) pre-populated.
Runtime config
POST /_ministack/config mutates a limited set of keys without restarting. Example:
curl -X POST http://localhost:4566/_ministack/config \
-H 'Content-Type: application/json' \
-d '{"key":"athena.engine","value":"duckdb"}'
Whitelisted prefixes include athena.*, stepfunctions.*, and lambda_svc.*. Tests use this to flip a single knob without tearing down the container.
grep -r "os.environ" ministack/ gives the definitive list.