DEV Community

Cover image for MiniStack: Free Local AWS Emulator + Testcontainers Module + AWS CLI Built In
Nahuel Nucera
Nahuel Nucera

Posted on

MiniStack: Free Local AWS Emulator + Testcontainers Module + AWS CLI Built In

4 releases in a weekend: Testcontainers Java module, AWS CLI bundled, Step Functions intrinsics, RDS Data stubs. Free, open-source, MIT licensed.

TL;DR

We shipped 4 releases this weekend (v1.2.6 through v1.2.9):

  1. org.ministack:testcontainers-ministack:0.1.0 on Maven Central
  2. 62 bug fixes found by running 2,490 tests across all 41 services
  3. AWS CLI bundled in the Docker image — init scripts just work
  4. Step Functions intrinsics — 7 new functions (ArrayContains, MathAdd, UUID, etc.)
  5. RDS Data API stubs — test database provisioning without Docker-in-Docker

What is MiniStack?

MiniStack is a free, MIT-licensed local AWS emulator. One Docker image, one port (4566), 41 services. It started as a response to LocalStack moving core services behind a paid plan.

  • Image size: 269MB (was 242MB before CLI)
  • Startup time: <2 seconds
  • Services: S3, DynamoDB, SQS, SNS, Lambda, Step Functions, CloudFormation, EC2, ECS, and 32 more
  • Docker: ministackorg/ministack
  • GitHub: ministackorg/ministack

No license keys. No pro tiers. Just run it.

docker run -d -p 4566:4566 ministackorg/ministack
Enter fullscreen mode Exit fullscreen mode

Testcontainers Module

<dependency>
    <groupId>org.ministack</groupId>
    <artifactId>testcontainers-ministack</artifactId>
    <version>0.1.0</version>
    <scope>test</scope>
</dependency>
Enter fullscreen mode Exit fullscreen mode
@Testcontainers
class S3IntegrationTest {

    @Container
    static MiniStackContainer ministack = new MiniStackContainer("ministackorg/ministack:latest");

    @Test
    void shouldCreateBucketAndPutObject() {
        S3Client s3 = S3Client.builder()
                .endpointOverride(ministack.getEndpoint())
                .credentialsProvider(ministack.getCredentialsProvider())
                .region(Region.US_EAST_1)
                .build();

        s3.createBucket(b -> b.bucket("test-bucket"));
        s3.putObject(
                b -> b.bucket("test-bucket").key("hello.txt"),
                RequestBody.fromString("Hello MiniStack!")
        );

        String body = s3.getObjectAsBytes(
                b -> b.bucket("test-bucket").key("hello.txt")
        ).asUtf8String();

        assertEquals("Hello MiniStack!", body);
    }
}
Enter fullscreen mode Exit fullscreen mode

Works with JUnit 5 and Spring Boot's @DynamicPropertySource. The container starts in under 2 seconds.


AWS CLI Bundled (v1.2.9)

The Docker image now ships with AWS CLI v1. Init scripts just work without any credential configuration:

# ready.d/01-create-resources.sh
aws s3 mb s3://my-bucket
aws sqs create-queue --queue-name my-queue
Enter fullscreen mode Exit fullscreen mode
# ready.d/02-seed-data.py
import boto3, os
s3 = boto3.client("s3", endpoint_url=os.environ["AWS_ENDPOINT_URL"])
s3.put_object(Bucket="my-bucket", Key="config.json", Body=b'{"env": "local"}')
Enter fullscreen mode Exit fullscreen mode

Both .sh and .py init scripts are supported. AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION, and AWS_ENDPOINT_URL are automatically set for init scripts.


The Flea Hunt: 62 Bugs Found and Fixed

We ran what we call a "Flea Hunt" — 2,490 tests across all 41 services using 10 parallel MiniStack instances. Some highlights:

  • S3 versioningGetObject by VersionId was returning the wrong version. Delete markers were missing entirely from ListObjectVersions.
  • Lambda — internal _request_id was leaking into handler events. PublishVersion ARN was missing the :version qualifier.
  • DynamoDB — Go SDK v2 requires a CRC32 header on every response. Without it, the SDK throws an integrity error before your code sees anything.
  • Java SDK v2time.time() floats in scientific notation broke the timestamp parser across 14 services. Fixed with int(time.time()).
  • EC2 — TagSpecifications were silently ignored on 11 create operations. DeleteVpc succeeded even with subnets attached.

After the fixes: 1,327 regression tests (1,196 Python + 131 Java), zero failures.


Quick Start

Docker:

docker run -d -p 4566:4566 ministackorg/ministack
Enter fullscreen mode Exit fullscreen mode

Terraform:

provider "aws" {
  endpoints {
    s3       = "http://localhost:4566"
    dynamodb = "http://localhost:4566"
    sqs      = "http://localhost:4566"
  }
  region     = "us-east-1"
  access_key = "test"
  secret_key = "test"
}
Enter fullscreen mode Exit fullscreen mode

Links

If you give it a try, open an issue or tell us which service you want improved next.

MiniStack is MIT licensed. Star us on GitHub if this saves you from mocking AmazonS3Client one more time.

Top comments (0)