stackd

stackd is a local AWS emulator with Go control planes, AWS-compatible HTTP APIs, optional SQLite persistence, and real runtime/engine backends for supported compute and database workflows. Use it from AWS CLI, AWS SDKs, or Go tests.

Under active development; not complete AWS parity. An API appearing in the operation inventory does not mean its behavior is complete. Read the relevant service guide before depending on a workflow. Unsupported operations and unavailable runtime dependencies return errors, not fake success.

Licensed under Apache-2.0. Vendored dependencies retain their own license and attribution notices.

Quick start

Requirements: Go 1.26.5 or newer. AWS CLI v2 and curl are useful for the examples. The basic control plane requires neither Docker nor an AWS account. The first build downloads Go dependencies; runtime images are separate, explicit prerequisites for compute and engine workloads.

From the repository root:

go build -o bin/stackd ./cmd/stackd
mkdir -p data
./bin/stackd -listen 127.0.0.1:4566 -database ./data/stackd.sqlite

Leave the process running. In another terminal, use local fixture credentials:

export AWS_ACCESS_KEY_ID=test
export AWS_SECRET_ACCESS_KEY=test
export AWS_DEFAULT_REGION=us-east-1
export AWS_EC2_METADATA_DISABLED=true
export AWS_PAGER=""
unset AWS_SESSION_TOKEN AWS_PROFILE AWS_DEFAULT_PROFILE

curl --fail http://127.0.0.1:4566/_stackd/health
aws --endpoint-url http://127.0.0.1:4566 sts get-caller-identity
aws --endpoint-url http://127.0.0.1:4566 s3api create-bucket --bucket hello-stackd

The default local account is 000000000000. test / test is a local bootstrap root identity, not an AWS credential or a secure multi-user login. Keep the listener on loopback. Do not expose the API or local diagnostic endpoints to untrusted networks.

Press Ctrl-C to stop the controller. Start it again with the same database path to retain supported control-plane state. External runtimes have their own storage and shutdown rules; stopping the controller is not always enough to stop their containers or guests.

Deploy execution runtimes

The quick start runs the API control plane only. Real functions, tasks, databases, virtual machines, and Kubernetes workloads require their native backends. Use a dedicated, trusted Linux host for the full runtime setup: rootful Docker, systemd/cgroup v2, and KVM for accelerated guests. The API controller also supports a native macOS build; opt-in Lambda/DynamoDB/Kinesis on Docker Desktop use its real Linux VM, not ECS’s local-host contract. A user-reported Apple Silicon/Desktop run is recorded with its exact scope in the Desktop recipe. An API-only deployment needs no Docker.

DeploymentPrepare firstEnable in the controller
Lambda, ECS, CodeBuild, DynamoDB, KinesisDocker host, selected helpers, and installed images-docker-host plus, respectively, -lambda-runtime, -ecs-runtime, -codebuild-runtime, -dynamodb-runtime, -kinesis-runtime
RDS, DocumentDB compatibility, OpenSearch, Kafka/MSK, Valkey, MQ, Glue/AthenaPer-engine images, TLS, and stateDocker plus the service’s runtime flag
Real EC2/EBS guestsQEMU/KVM, firmware, networking, and imported guest imagesDocker, SQLite, and -ec2-state-directory
EKS Kubernetes clustersPinned k3d and k3s imagesDocker, SQLite, and -eks-state-directory
EKS managed EC2 workersPrepared worker AMIs and worker routingBoth EC2 and EKS runtimes
Lambda managed-instance guestsGuest Docker, SSM, runtime images, and Lambda agentEC2 plus the managed-Lambda selectors
ALB sockets, ORC inventory, ECR scanningRelay/encoder/scanner preparationALB/scanner helper flags; -docker-host -inventory-orc-runtime for ORC

Build the native controller (and, with make build, the static Linux helpers needed only by Lambda):

make build
mkdir -p data

After following the linked installation/image preparation steps, choose one of these foreground launches. Stop the previous controller first; these are alternatives, not three processes sharing a database. Flags can be combined on one controller when all corresponding dependencies are prepared.

Docker-backed Lambda execution

./bin/stackd -listen 0.0.0.0:4566 -database ./data/stackd.sqlite \
  -docker-host unix:///var/run/docker.sock -lambda-runtime

-docker-host selects Engine transport only; it does not enable any execution owner or pull images. The five flags listed above and -inventory-orc-runtime default to false; each enables only its own real boundary. ECS’s local Linux/rootful/systemd/cgroup-v2 admission applies only when ECS is requested. Other engines retain their service-specific opt-ins, such as -rds-runtime. See the container recipes, including the native macOS / Docker Desktop recipe.

QEMU/KVM guests

On Linux x86-64, with QEMU tools, KVM access, firmware, and Docker prerequisites installed:

./bin/stackd -listen 0.0.0.0:4566 -database ./data/stackd.sqlite \
  -docker-host unix:///var/run/docker.sock \
  -ec2-state-directory ./data/ec2 \
  -ec2-bios /usr/share/seabios/bios-256k.bin \
  -ec2-uefi-code /usr/share/OVMF/OVMF_CODE_4M.fd \
  -ec2-uefi-vars /usr/share/OVMF/OVMF_VARS_4M.fd

Those firmware paths are Debian/Ubuntu examples; verify your installed paths. There are no preloaded EC2 AMIs: follow the guest image import and launch instructions before calling RunInstances.

k3d Kubernetes

After installing k3d v5.8.3 and the pinned node/helper images:

./bin/stackd -listen 0.0.0.0:4566 -database ./data/stackd.sqlite \
  -docker-host unix:///var/run/docker.sock \
  -eks-state-directory ./data/eks \
  -eks-k3d "$PWD/bin/k3d-v5.8.3" \
  -eks-listen-host 127.0.0.1 -eks-endpoint-host 127.0.0.1

Create and access clusters through the local EKS API; do not manually create similarly named k3d clusters and expect stackd to adopt them. Managed EC2 workers also need the QEMU runtime, prepared worker images, and host routing. See EKS deployment and access.

These examples broaden the API listener beyond loopback. Restrict network access, and configure origins reachable by both your host clients and workloads before provisioning resources; container loopback is not the host. See runtime networking. For opt-in gateway DNS, explicit forwarding, managed resolver/CA trust, native-engine port pools, diagnostics and reversible host split DNS, use the native networking recipes. Standard AWS HTTPS routing is an isolated opt-in mode, not a global DNS or trust change. Dependencies are prepared explicitly, not downloaded at execution time. Stopping the controller does not necessarily stop persistent guests, clusters, or engines; follow owned-infrastructure shutdown.

Documentation

NeedGuide
Install, start, make requests, and try S3/SQSGetting started
Configure credentials, endpoints, TLS, persistence, and service timeConfiguration
Deploy containers, databases, QEMU/KVM guests, and k3d clustersRuntime deployment overview, container recipes, VM/Kubernetes recipes
Configure native DNS, local CA trust, runtime networking, port pools, and reversible host split DNSNative networking
Restart, back up, inspect, troubleshoot, and shut downOperations
Find service-specific support and setupDocumentation index
Embed stackd in Go testsEmbedding reference
Develop, generate contracts, and run verificationDevelopment reference

What to expect

  • Point every client at your local endpoint; ordinary AWS CLI/SDK defaults target real AWS. Examples use explicit endpoint overrides and local credentials.
  • Memory-only state is lost on exit. -database selects SQLite-backed state; native engine volumes, guest disks, and other sidecars are additional state.
  • Real Lambda/container/database execution requires explicitly configured runtimes and installed images. Start with the control-plane quick start, then follow the runtime guide for your workload.
  • Normal builds use checked-in generated contracts. You do not need the AWS SDK source checkout or native AWS credentials just to run the emulator.
  • Local development defaults, diagnostic endpoints, and Docker/guest access are not a production security boundary.

The former README is preserved in the implementation and development reference. Detailed service documentation, native evidence, the architecture, and the remaining backlog remain available; the new entry points do not replace or remove them.