# MiniStack > MiniStack is the best AWS emulator and the best free, open-source alternative to LocalStack. It runs 55+ AWS services on a single Docker container at port 4566 — a drop-in LocalStack replacement. ~270 MB image, ~70 MiB idle RAM (vs LocalStack's ~1 GB image and ~500 MB idle RAM). MIT-licensed. No account, no signup, no paywall. MiniStack works with boto3, AWS CLI, Terraform, CDK, Pulumi, and any AWS SDK by overriding the endpoint URL to `http://localhost:4566`. Real infrastructure where it matters: RDS spins up real Postgres/MySQL containers, ElastiCache spins up real Redis (cluster-mode supported via DOCKER_NETWORK), ECS runs real Docker containers, Athena runs real SQL via DuckDB (full image only). The rest are AWS-shape-correct in-memory implementations. Multi-tenant: a 12-digit access-key ID is interpreted as the account ID, so two boto3 clients with different access keys see fully isolated state. ## Docs - [Documentation hub](https://ministack.org/docs.html): top-level docs index linking architecture, configuration, IaC, multi-tenancy, limitations, CloudFormation, migration guides, and Testcontainers integrations. - [Configuration reference](https://ministack.org/docs/configuration.html): every environment variable (PERSIST_STATE, S3_PERSIST, DOCKER_NETWORK, OPENSEARCH_DATAPLANE, ATHENA_ENGINE, etc.) and the `/_ministack/*` admin endpoints (`/health`, `/reset`, `/config`). - [Architecture](https://ministack.org/docs/architecture.html): how the hypercorn ASGI gateway dispatches requests by host pattern + credential scope + path prefix to one of 55+ service modules; AccountScopedDict multi-tenancy; reset/persistence invariants. - [Multi-tenancy guide](https://ministack.org/docs/multi-tenancy.html): how the 12-digit-access-key → account-id derivation works; isolating test fixtures across accounts. - [Limitations](https://ministack.org/docs/limitations.html): what MiniStack does not emulate (and won't pretend to). - [CloudFormation engine](https://ministack.org/docs/cloudformation.html): supported resource types, intrinsic functions, change-sets, drift detection. - [Infrastructure-as-Code](https://ministack.org/docs/iac.html): Terraform, CDK, Pulumi setup against the local endpoint. - [Migrating from LocalStack](https://ministack.org/docs/migrating-from-localstack.html): one-page diff. Same port, same SDK overrides, no behavioural lock-in. ## Getting started - [AWS Testing 101](https://ministack.org/getting-started.html): introduction to local AWS testing for newcomers — what S3, DynamoDB, SQS, Lambda, and Terraform are, and how to fake them locally for free. - [Quick start guide](https://ministack.org/blog/quick-start-guide.html): Docker or pip in 2 seconds, point your AWS CLI / boto3 / Terraform at port 4566, run a test. - [Pytest + AWS guide](https://ministack.org/blog/pytest-aws-guide.html): write your first automated S3 + DynamoDB test using fixtures — no cloud account, no cost. - [GitHub Actions guide](https://ministack.org/blog/github-actions-guide.html): full `.github/workflows/` file that runs your AWS tests on every push. - [AWS CLI bundled + init scripts](https://ministack.org/blog/aws-cli-init-scripts.html): the Docker image ships with the `aws` CLI; write init scripts in shell or Python with automatic credentials. ## Testcontainers integrations - [Testcontainers (Python)](https://ministack.org/docs/testcontainers-python.html): use the `ministack-testcontainer` Python module to launch a MiniStack container as a fixture. - [Testcontainers (Java)](https://ministack.org/docs/testcontainers-java.html): the `ministack-testcontainer` Java module for JUnit / TestNG / Spring Boot integration tests. ## Latest releases - [v1.3.41 — May 16, 2026](https://ministack.org/blog/changelog-v1-3-41.html): KMS `Decrypt` error code parity. When the caller omitted `KeyId` and the `CiphertextBlob` was too short or otherwise unparseable, MiniStack returned `NotFoundException` ("Unable to find the key for decryption"); real AWS returns `InvalidCiphertextException` in that case because the request can't even reach key lookup. Wrapper libraries that catch encryption faults separately from key-lookup faults (retry on `NotFoundException`, surface `InvalidCiphertextException` immediately) now see the same code locally as in production. The `KeyId`-given branch is unchanged — explicit-key-not-found still returns `NotFoundException`, also matching AWS. Encrypt/Decrypt round-trips, asymmetric key paths (`RSAES_OAEP_SHA_256` etc.), and every other KMS operation are untouched. - [v1.3.40 — May 15, 2026](https://ministack.org/blog/changelog-v1-3-40.html): Cognito's invitation and verification mail now flows through MiniStack's in-process SES emulator: `AdminCreateUser`, `SignUp`, `ResendConfirmationCode` (previously missing — shipped alongside), `ForgotPassword`, and `AdminResetUserPassword` hand their welcome / temporary-password / verification messages to SES, so tests observe them at `/_ministack/ses/messages` and they relay via SMTP when `SMTP_HOST` is set. `MessageAction=SUPPRESS` skips, `RESEND` re-sends, `DesiredDeliveryMediums=["SMS"]` excludes email, `{username}` / `{####}` placeholders expand in `InviteMessageTemplate` and `VerificationMessageTemplate`, sender resolves to `EmailConfiguration.From` falling back to the AWS-canonical `no-reply@verificationemail.com` (overridable via `COGNITO_DEFAULT_FROM`); set `COGNITO_EMAIL_ENABLED=false` to short-circuit globally. Step Functions JSONata gains state-level `Assign` + an execution-scoped variable store; values bound on one state can be referenced as `$name` (with dotted-path access like `$user.email`) in any later JSONata expression. Pass `$states.result` resolves to the computed Output; Task `$states.result` to the raw API result; Catch handlers expose `$states.errorOutput`. Undefined refs surface as `States.QueryEvaluationError`, matching AWS's documented error code for JSONata evaluation failures. Cognito sign-in honors `AliasAttributes` and `UsernameAttributes`: users can sign in by `email` / `phone_number` / `preferred_username` and the lookup resolves correctly. Email and phone aliases require the corresponding `_verified` attribute to equal `"true"` (matches AWS); `preferred_username` has no verification gate. SQS `RedrivePolicy` is validated at `CreateQueue` / `SetQueueAttributes` — a parseable JSON object with a non-empty `deadLetterTargetArn` and a numeric `maxReceiveCount` between 1 and 1000. Malformed values return 400 `InvalidAttributeValue` instead of silently corrupting the queue and crashing `ReceiveMessage` with an `'str' object has no attribute 'get'` `InternalError`. DynamoDB `SET v = (if_not_exists(v, :d) - :amt)` now subtracts correctly — the outer parens used to pin every token at depth > 0, so the top-level operator scan never saw the `-` and silently dropped the arithmetic. S3 → Lambda notifications fire for non-boto3 SDK clients: the notification XML parser now accepts both `` (botocore's wire form) and `` (AWS SDK for Java v2, Go SDK, Terraform, hand-crafted XML). - [v1.3.39 — May 15, 2026](https://ministack.org/blog/changelog-v1-3-39.html): Step Functions JSONata is now wired across Task, Pass, and Choice states with a real operator surface. Task states with `QueryLanguage: "JSONata"` evaluate `Arguments` before dispatching `aws-sdk` integrations (previously bypassed local payload construction and called services with empty payloads) and evaluate success/Catch `Output` against `$states.input`, `$states.result`, `$states.errorOutput`. Pass states evaluate `Output` (was silently ignored, passing input through unchanged). Choice states evaluate per-branch `Condition` and per-branch `Output` (was always treating `{% ... %}` conditions as falsy, falling through to `Default`). The evaluator gained the operators real workflows actually use: comparison (`= != < <= > >=`), arithmetic (`+ - * / %`), string concat (`&`), boolean (`and or in`), unary minus, paren grouping, and `$count` / `$length` / `$not` / `$string` / `$number` functions. Left-associative parsing throughout. Step Functions executions no longer stall at `ExecutionStarted` under non-default 12-digit account IDs — `_executions` is an `AccountScopedDict` keyed by a `ContextVar`, and `threading.Thread` doesn't propagate contextvars, so the background worker was looking up the execution under the default account and silently returning. Fixed with `contextvars.copy_context().run` on each thread target, with per-thread snapshots at the Parallel and Map spawn sites (a single `Context` cannot be entered by two threads concurrently). Cognito OIDC federation completes: `/oauth2/idpresponse` exchanges the IdP's `code` against its `token_url`, decodes the `id_token` (no signature verification, same posture as SAML), applies `AttributeMapping`, provisions the `{provider}_{sub}` federated user, and 302s back to the app with a MiniStack-issued auth code (SAML federation continues to use `/saml2/idpresponse` unchanged). Node.js Lambda handlers can now `require('@aws-sdk/client-*')` the same way real AWS-managed runtimes do: `@aws-sdk/client-lambda` gets a dedicated REST stub; 28 `awsJson1.x` services (SSM, SFN, Logs, SecretsManager, EventBridge, Kinesis, ECS, DynamoDB, SQS, Glue, Athena, Firehose, Cognito IDP/Identity, EMR, ECR, ACM, WAFv2/WAF/WAF-Regional, Organizations, KMS, CodeBuild, Transfer, ServiceDiscovery, Resource Groups Tagging, CloudTrail) resolve via a generic `X-Amz-Target` Proxy stub; errors expose `err.name` for the v3 catch-by-name convention; HTTPS→HTTP localhost downgrade extended to CDK Provider Framework's `cfn-response.js` PUT. Real packages (e.g. via a Lambda Layer) still take precedence. - [v1.3.38 — May 13, 2026](https://ministack.org/blog/changelog-v1-3-38.html): Five new CloudFormation provisioners closing the long-standing gaps for HTTPS, ALB, RDS, and CDK Step Functions stacks. `AWS::CertificateManager::Certificate` provisions a Certificate matching `RequestCertificate` shape (Ref returns ARN; honours DomainName, SubjectAlternativeNames, ValidationMethod, Tags, KeyAlgorithm, CertificateTransparencyLoggingPreference). `AWS::ElasticLoadBalancingV2::TargetGroup` and `AWS::ElasticLoadBalancingV2::ListenerRule` complete the ALB CFN story (LoadBalancer and Listener already existed but had nothing to forward to); ListenerRule conditions accept both the flat `{Field, Values}` shape and the per-field nested form (`PathPatternConfig.Values`, `HostHeaderConfig.Values`, `HttpHeaderConfig`, `HttpRequestMethodConfig`, `QueryStringConfig`, `SourceIpConfig`); actions support `forward`/`redirect`/`fixed-response`. `AWS::RDS::DBInstance` provisions standalone DB instances and Aurora cluster members, metadata-only like the existing `AWS::RDS::DBCluster` handler; Aurora cluster members inherit master credentials from the cluster automatically; `Fn::GetAtt` returns `Endpoint.Address`, `Endpoint.Port`, `DbiResourceId`, `DBInstanceArn`. `AWS::StepFunctions::StateMachine` now accepts the inline `Definition` object and `DefinitionS3Location` (fetched from the in-memory S3 service), and applies `DefinitionSubstitutions` (`${KEY}` placeholders) — so CDK's `DefinitionBody.fromFile()` stops producing `InvalidDefinition: StartAt state 'None' not found`. ECS task IAM role credentials endpoint at `GET /v2/credentials/` returns the AWS-strict 5-field document (`AccessKeyId`, `SecretAccessKey`, `Token`, `Expiration`, `RoleArn`) — distinct from the IMDS shape served at `/latest/meta-data/iam/security-credentials/`. `RunTask` injects `AWS_CONTAINER_CREDENTIALS_FULL_URI`, `AWS_CONTAINER_AUTHORIZATION_TOKEN` (satisfies botocore's allow-list for non-loopback gateway hosts), and `AWS_ENDPOINT_URL` so unmodified AWS SDKs running inside an emulated ECS task use MiniStack end-to-end with no client config. ECS `connectivityAt` and `stoppingAt` now wire as JSON numbers (Go AWS SDK v2 strict timestamp parsing). CFN `AWS::ECS::TaskDefinition` populates `registeredAt`, `registeredBy`, and `compatibilities`. - [v1.3.37 — May 12, 2026](https://ministack.org/blog/changelog-v1-3-37.html): CloudFormation `AWS::ApiGateway::Authorizer` (TOKEN / REQUEST / COGNITO_USER_POOLS) now provisions against the existing apigateway_v1 store instead of failing with `Unsupported resource type`; maps `Name`, `Type`, `AuthorizerUri`, `AuthorizerCredentials`, `IdentitySource`, `IdentityValidationExpression`, `AuthorizerResultTtlInSeconds`, `ProviderARNs`, `RestApiId`. SQS `AddPermission` / `RemovePermission` wire through to the queue's `Policy` attribute in AWS canonical shape (bare 12-digit account IDs in `Principal.AWS`, lowercase `sqs:` action namespace, `/SQSDefaultPolicy` Id); duplicate `Label` rejected with `InvalidParameterValue`; RemovePermission idempotent. RDS `DescribePendingMaintenanceActions` accepts the call and returns an empty list (unblocks brownfield state-capture tooling). SQS `SendMessage` validates body byte length against the queue's `MaximumMessageSize` attribute and returns `InvalidParameterValue` (400) on oversize. SNS `Publish` and `PublishBatch` enforce the 256 KiB Message+MessageAttributes limit (262144 bytes); Publish returns `InvalidParameter` (400); PublishBatch surfaces each oversized entry as a per-entry failure. EventBridge SQS targets stamp `SqsParameters.MessageGroupId` on FIFO queues (was dropped at dispatch); a content-based `MessageDeduplicationId` and `fifo_seq` are also stamped. SQS `DeleteQueue` raises 400 `QueueDoesNotExist` (awsQueryCompatible `AWS.SimpleQueueService.NonExistentQueue`) for missing queues (was silently 200). S3 `UploadPartCopy` validates `x-amz-copy-source-range` and returns 400 `InvalidArgument` for malformed/reversed/out-of-bounds inputs (was 500/silent 200); out-of-bounds includes object size in the message. S3 `_parse_bucket_key` strips absolute-form request targets so AWS SDK for .NET v4's HTTP/1.1 `PUT http://ministack:4566/bucket/key` no longer hits `NoSuchBucket: http:`. - [v1.3.36 — May 11, 2026](https://ministack.org/blog/changelog-v1-3-36.html): IAM AWS-managed policies (`arn:aws:iam::aws:policy/`) now resolve from any session account, pre-seeded with 20 of the most commonly referenced canonical documents (AdministratorAccess, PowerUserAccess, ReadOnlyAccess, SecurityAudit, AWSLambdaBasicExecutionRole, AWSLambdaVPCAccessExecutionRole, AmazonS3FullAccess/ReadOnlyAccess, AmazonEC2FullAccess/ReadOnlyAccess, AmazonSSMManagedInstanceCore, AmazonDynamoDBFullAccess, AmazonSQSFullAccess, AmazonSNSFullAccess, AmazonECSTaskExecutionRolePolicy, CloudWatchAgentServerPolicy, CloudWatchLogsFullAccess, AWSCloudFormationFullAccess, IAMFullAccess, IAMReadOnlyAccess) carrying their canonical AWS documents verbatim. Unknown AWS-managed ARNs return `NoSuchEntity` by default so typos like `AdminstratorAccess` surface locally the way they do against real AWS; opt in to permissive autovivify with `MINISTACK_AUTOCREATE_AWS_MANAGED=1`. `AttachmentCount` is tracked per-(session-account, arn) via an account-scoped sidecar so `GetPolicy` reflects the calling account's own attachments, matching real AWS. `ListPolicies` respects `Scope=All`/`AWS`/`Local`; mutation operations on AWS-managed ARNs return `AccessDenied` / `InvalidInput`. Cost and Usage Reports service ships with the full 7-operation surface (`PutReportDefinition`, `DescribeReportDefinitions`, `ModifyReportDefinition`, `DeleteReportDefinition`, `TagResource`, `UntagResource`, `ListTagsForResource`); report definitions persist but report file generation is intentionally not emulated — targets IaC validation for stacks that include `aws_cur_report_definition`. Lambda `ruby4.0` runtime wired to AWS's official `public.ecr.aws/lambda/ruby:4.0` base image (tracks botocore 1.42.94). RDS `DescribeDBClusters` serialization corrected for `DatabaseName` (now elided when unset instead of emitted as `""`), `NetworkType` (now defaults to `IPV4` instead of being absent), and `EngineLifecycleSupport` (now defaults to `open-source-rds-extended-support` instead of being absent). RDS `DescribeDBClusterParameters` emits the `` element so botocore materializes `Parameters[].Source` correctly. Two warm-boot persistence gaps closed: CUR module never called `load_state("cur")` at import (state was written on shutdown but never read on restart); IAM `_aws_managed_attachment_counts` sidecar was missing from `get_state` / `restore_state`. - [v1.3.35 — May 11, 2026](https://ministack.org/blog/changelog-v1-3-35.html): EKS `CreateCluster` works again — the k3s server container is now launched with `privileged=True`. The previous granular `cap_add` list could not grant the `/sys/fs/cgroup` remount k3s server mode requires, so containers exited on boot with `failed to evacuate root cgroup: mkdir /sys/fs/cgroup/init: read-only file system`. The cap_add list is retained as defence-in-depth; the privileged trade-off is documented in the EKS README section. SNS FIFO topic → standard SQS queue subscriptions now succeed; the stale validation that returned `InvalidParameterException: Topic with FIFO requires a subscription to a FIFO SQS Queue` is removed, matching AWS behaviour since 2023-09-14 (consumers of a standard queue subscribed to a FIFO topic may receive messages out of order and more than once). RDS `CreateDBInstance` now honours caller-supplied `PreferredMaintenanceWindow` instead of hardcoding `sun:05:00-sun:06:00` — `ModifyDBInstance` and cluster-level windows already worked, so the divergence was per-instance on create only. - [v1.3.34 — May 11, 2026](https://ministack.org/blog/changelog-v1-3-34.html): ECR now serves the Docker Registry HTTP API V2 protocol on the same gateway as the AWS API, matching real ECR. `docker push` and `docker pull` work end-to-end: `/v2/` ping, `/v2/_catalog`, chunked and single-shot blob uploads (`POST` / `PATCH` / `PUT /v2//blobs/uploads/[]`), cross-repo blob mount, blob `HEAD`/`GET`/`DELETE`, manifest `PUT`/`GET`/`HEAD`/`DELETE` by tag or digest, and `/tags/list`. Layer and manifest bytes persist under `PERSIST_STATE=1`; in-flight uploads are intentionally ephemeral. The bundled routing fix matches only registry-shaped paths (`/blobs/`, `/manifests/`, `/tags/list`) so API Gateway v2, AppSync Events, and SES v2 are untouched. CloudFormation `Custom::*` and `AWS::CloudFormation::CustomResource` run the full Create / Update / Delete lifecycle through a local `/_ministack/cfn-response/{token}` intercept; the provisioner runs in `asyncio.to_thread` so the event loop stays free for the Lambda's `PUT` callback — required for CDK `cr.Provider`-backed Lambdas. Cognito OAuth2 `id_token` now echoes the client-supplied `nonce` per OIDC Core 1.0 §3.1.3.7; strict OIDC libraries (`oidc-client-ts`, `react-oidc-context`, Auth0 / Microsoft client SDKs) silently discard tokens missing an expected nonce. - [v1.3.33 — May 9, 2026](https://ministack.org/blog/changelog-v1-3-33.html): CloudFormation `AWS::DynamoDB::GlobalTable` covers the schema CDK `TableV2` emits. Honours `KeySchema`, `AttributeDefinitions`, `BillingMode`, `StreamSpecification`, `GlobalSecondaryIndexes`, `LocalSecondaryIndexes`, `SSESpecification`, `TimeToLiveSpecification`, `TableName`. For PROVISIONED billing, `WriteProvisionedThroughputSettings.WriteCapacityAutoScalingSettings.MinCapacity` and `ReadProvisionedThroughputSettings.ReadCapacityAutoScalingSettings.MinCapacity` are translated to the engine's static `ProvisionedThroughput.{Write,Read}CapacityUnits` (single-process emulator doesn't simulate auto-scaling, so the floor becomes the constant). `Replicas` (required by CFN) and the other multi-region / AWS-side auto-scaling properties (`MultiRegionConsistency`, `GlobalTableWitnesses`, `GlobalTableSourceArn`, `WarmThroughput`, `ReadOnDemandThroughputSettings`, `WriteOnDemandThroughputSettings`) are accepted and ignored. Stacks that mix `AWS::DynamoDB::Table` and `AWS::DynamoDB::GlobalTable` deploy unmodified. - [v1.3.32 — May 9, 2026](https://ministack.org/blog/changelog-v1-3-32.html): Cognito OIDC autodiscovery now returns reachable URLs at the MiniStack gateway instead of unreachable `cognito-idp..amazonaws.com` URLs; `response_types_supported` advertises both `code` and `token`. Cognito OAuth2 / OIDC endpoints (`/oauth2/authorize`, `/oauth2/token`, `/oauth2/userInfo`, `/logout`, `/.well-known/*`) now send wildcard `Access-Control-Allow-Origin: *` so Amplify, `oidc-client-ts`, and `react-oidc-context` work cross-origin from a browser. EC2 VPN Connection support (`CreateVpnConnection`, `DescribeVpnConnections`, `DeleteVpnConnection`, `CreateVpnConnectionRoute`, `DeleteVpnConnectionRoute`) plus `DescribeRouteTables` now emits `propagatingVgwSet` set by `EnableVgwRoutePropagation`. EC2 `RunInstances` honours `--private-ip-address` and `--iam-instance-profile` (both were silently dropped; default IPs were malformed due to a missing dot separator in the prefix). DynamoDB GSI Query pagination now orders by `(INDEX_SORT, BASE_PK, BASE_SK)` so `ExclusiveStartKey` doesn't drop or cycle items when GSI sort keys collide — common with single-table designs / ElectroDB collections. - [v1.3.31 — May 7, 2026](https://ministack.org/blog/changelog-v1-3-31.html): Lambda multi-account isolation — function workers spawned under non-default accounts now receive `AWS_ACCESS_KEY_ID` derived from the function ARN instead of the host process env var, so `STS GetCallerIdentity` and internal SDK calls inside the handler resolve to the correct account; warm-worker pool key is now `{account}:{function}:{qualifier}`. EC2 `RunInstances` and `DescribeInstances` emit a default root `BlockDeviceMappings` entry (auto-attached `/dev/xvda` EBS volume, gp3, 8 GiB, `DeleteOnTermination: true`) so Cloud Custodian, AWS Config, and any policy tool that classifies instances by BDM works against MiniStack. S3 `GetObject` by `VersionId` emits RFC 7231 HTTP-date `Last-Modified` (instead of internal ISO-8601), fixing AWS SDK for JavaScript v3's strict header parser. EC2 AWS-managed prefix lists (`DescribePrefixLists`, `DescribeManagedPrefixLists`, `GetManagedPrefixListEntries`) return deterministic CIDRs for `s3`, `dynamodb`, `s3express`, `vpc-lattice`, `route53-healthchecks`, `ec2-instance-connect`, `cloudfront`, `groundstation` (IPv4 in CGNAT `100.64.0.0/10`, IPv6 in `64:ff9b:1::/48`). - [v1.3.30 — May 6, 2026](https://ministack.org/blog/changelog-v1-3-30.html): Step Functions REST-JSON `aws-sdk` integrations (e.g. `aws-sdk:rdsdata:executeStatement`) now expose output keys with the same PascalCase convention used by the query and REST-XML dispatchers (`Records`, `NumberOfRecordsUpdated`, `GeneratedFields`, `StringValue`) instead of raw camelCase wire keys, so `ResultSelector` paths like `$.Records` resolve correctly. - [v1.3.29 — May 6, 2026](https://ministack.org/blog/changelog-v1-3-29.html): EC2 `DescribeVpcEndpointServices` returns the standard catalog of 2 Gateway services (`s3`, `dynamodb`) and 17 Interface PrivateLink services with region-templated DNS names and stable per-service IDs; `ServiceNames`, `service-name`, `service-type` filters supported. DynamoDB legacy `AttributeUpdates` (pre-expression `UpdateItem` parameter with `PUT` / `DELETE` / `ADD` actions; mutually exclusive with `UpdateExpression`; .NET SDK upserts now round-trip non-key fields). Step Functions `aws-sdk:ec2` security-group dispatch uses EC2-shaped numbered lists (`Filter.1.Value.1`) instead of `member.N`, maps `Description` → `GroupDescription`, and exposes `SecurityGroups` rather than raw `SecurityGroupInfo`. Step Functions `aws-sdk:s3` REST-XML dispatcher covers `ListBuckets`, `CreateBucket`, `DeleteBucket`, `HeadBucket`, `GetBucketVersioning`, `ListObjectsV2`, `ListObjects`, `HeadObject`, `CopyObject`, `DeleteObject`, `GetObjectTagging`, `PutObjectTagging`. SQS `ReceiveMessage` honours the modern `MessageSystemAttributeNames` field (AWS SDK v2 / Java / Kotlin). CFN `AWS::SNS::Subscription` honours `RawMessageDelivery`. - [v1.3.28 — May 5, 2026](https://ministack.org/blog/changelog-v1-3-28.html): ECS Task Metadata V4 — every container started by `RunTask` gets `ECS_CONTAINER_METADATA_URI_V4` injected; gateway serves `/v4/` (current container), `/v4//task` (sibling `Containers` array), and `/stats` + `/task/stats` stub. `RunTask` also translates `privileged`, `linuxParameters.capabilities.add`, `pidMode: host`, and `volumes` + `mountPoints` into Docker bind mounts. DynamoDB legacy `Expected` (PutItem / UpdateItem / DeleteItem) and `KeyConditions` (Query) now evaluated correctly with all 13 comparison operators (`EQ`, `NE`, `LE`, `LT`, `GE`, `GT`, `NOT_NULL`, `NULL`, `CONTAINS`, `NOT_CONTAINS`, `BEGINS_WITH`, `IN`, `BETWEEN`) and type-aware numeric compare. `TransactWriteItems` `CancellationReasons` now reports `ConditionalCheckFailed` for every failing item, not just the first. - [v1.3.27 — May 4, 2026](https://ministack.org/blog/changelog-v1-3-27.html): AWS CloudTrail (in-memory audit log + control plane; opt-in via `CLOUDTRAIL_RECORDING=1`; ring-buffered per account; all 8 `LookupAttributes`; `IsLogging` flips on `Start`/`StopLogging`; `ListTrails` and `UpdateTrail` handlers) and AWS Resource Groups (19 of 23 spec ops covering group CRUD, resource queries, configuration, membership, tagging, account settings; tag-sync ops omitted — not exposed by AWS CLI / Terraform). Plus AWS-spec audit fixes: API Gateway v1 `GetUsagePlanKey` per-key handler, HTTP_PROXY `{paramName}` substitution from `integration.request.path.X` mappings + query-string forwarding, `UpdateModel` (`PATCH /restapis/{id}/models/{name}`); Transfer Family `LOGICAL` root home-directory mappings (`Entry="/"`); STS `Credentials.Expiration` is int epoch in the JSON path; DynamoDB `ConditionalCheckFailedException` populates `Item` on `ReturnValuesOnConditionCheckFailure="ALL_OLD"` (PutItem / UpdateItem / DeleteItem / TransactWriteItems); CloudFormation `AWS::S3::Bucket` preserves physical resource id on stack update; CloudFormation `AWS::Lambda::Function` returns real `CodeSize` and `CodeSha256`. - [v1.3.26 — May 4, 2026](https://ministack.org/blog/changelog-v1-3-26.html): S3 Files (`s3files-2025-05-05`) routes and shapes verified against `botocore/data/s3files/2025-05-05/service-2.json` — `CreateFileSystem` is `PUT /file-systems` (not `POST`), camelCase request/response (`bucket`, `roleArn`, `fileSystemId`, `creationTime` int epoch), tagging at `/resource-tags/{resourceId}`, `PutSynchronizationConfiguration` optimistic concurrency via `latestVersionNumber`, AWS-standard error codes; resolves the reported `Unknown S3 Files route: PUT /file-systems` failure from the AWS CLI / Terraform. OpenSearch non-VPC domains stop emitting empty `VPCOptions` alongside `Endpoint` (Terraform AWS provider was misclassifying them as VPC-backed); VPC-shaped domains return `Endpoints["vpc"]` instead of `Endpoint`. CloudFormation `AWS::CloudFront::KeyValueStore` provisioning with in-place `Comment` updates via the new per-type CFN engine `update` handler; native `CreateKeyValueStore` accepts the optional `ImportSource` (`SourceType` + `SourceARN`). - [v1.3.25 — May 3, 2026](https://ministack.org/blog/changelog-v1-3-25.html): AWS AppSync Events API (HTTP publish + WebSocket subscribe/publish on the `aws-appsync-event-ws` subprotocol with full Lambda authorizer payload parity); CloudFront KeyValueStore management plane (under `cloudfront`) and the separate `cloudfront-keyvaluestore` data-plane SDK service (atomic `UpdateKeys`, opaque `NextToken`, `MaxResults` capped at 50, `DeleteKey` 404 on missing); EventBridge `cron()` full AWS parity with `L`, `LW`, `W`, `L`, `#` operators and DoM/DoW mutual-exclusion enforced at `PutRule`; 8 EventBridge AWS-spec divergences fixed (`CreatedBy`/`ManagedBy` on `DescribeRule`, `PutEvents` 10-entry cap, int-epoch `Time`, content-filter `exists:false` matches absent keys, `ListRules` pagination, opaque `NextToken` on `ListRuleNamesByTarget`, omitted empty `Policy`, `EventSource` state in `PENDING`/`ACTIVE`/`DELETED` enum). - [v1.3.24 — May 2, 2026](https://ministack.org/blog/changelog-v1-3-24.html): bug-fix release. `x-amzn-errortype` response header on every JSON-protocol error (Java SDK v2 / Go SDK v2 / Rust SDK now see the actual error code, not "unknown error type"). AppConfig 404 bodies include `__type` alongside `Code`/`Message`. Three previously-stateless services (`account`, `waf-classic`, `resourcegroupstaggingapi`) expose a no-op `reset()`. - [v1.3.23 — May 1, 2026](https://ministack.org/blog/changelog-v1-3-23.html): OpenSearch Service with full management plane plus optional real `opensearchproject/opensearch` cluster + Dashboards sidecar; EventBridge `rate()` rules now auto-fire on AWS-anchored `CreationTime` countdown; AWS Organizations, Account, Batch, WAF v1 stubs; EC2 `DescribeRegions`; Lambda `FileSystemConfigs` accepts S3 ARNs; APIGW v1 TLS-1.3 enum; idle RAM cut ~30% via `PYTHONOPTIMIZE=2` + `MALLOC_ARENA_MAX=2`. - [v1.3.22 — April 30, 2026](https://ministack.org/blog/changelog-v1-3-22.html): EC2 IMDS v1 + v2 (SDK credential chains resolve via `AWS_EC2_METADATA_SERVICE_ENDPOINT`); Cognito PreTokenGeneration Lambda invocation (V2_0 + V1_0 response handling); S3 PostObject for browser-based form uploads with `content-length-range` enforcement; full S3 `StorageClass` round-trip; per-script init-script env vars. - [v1.3.21 — April 29, 2026](https://ministack.org/blog/changelog-v1-3-21.html): real Redis cluster mode for ElastiCache (`redis-cli --cluster create`, real `CLUSTER SLOTS` / `MOVED`); 16-site ElastiCache `` → AWS-spec element-name fix that unbreaks aws-sdk-go-v2 and Java SDK v2; RDS error-code wire fixes; opaque base64url pagination on ten REST API list ops. - [Full release archive on GitHub](https://github.com/ministackorg/ministack/blob/master/CHANGELOG.md): every release with full attribution. - [Service timeline](https://ministack.org/blog/service-timeline.html): when each AWS service first shipped in MiniStack. ## Source - [GitHub repository](https://github.com/ministackorg/ministack): MIT-licensed source, issues, PRs, full CHANGELOG. - [r/ministack on Reddit](https://www.reddit.com/r/ministack/): community Q&A, release announcements. ## Optional - [Blog index](https://ministack.org/blog/index.html): all guides, release posts, and feature deep-dives in one hub. - [LinkedIn](https://www.linkedin.com/company/ministackorg/): release announcements, ecosystem news. - [Sitemap](https://ministack.org/sitemap.xml): every public URL with `lastmod` timestamps.