A Local Development Toolbox with Docker Compose: Databases, Cloud Emulators and Mocks

How to build a reproducible local environment with Docker Compose for databases, MinIO, AWS/Azure/GCP emulators and WireMock, and what trade-offs it has.

A Local Development Toolbox with Docker Compose: Databases, Cloud Emulators and Mocks
Photo by Rubaitul Azad / Unsplash

How to build a reproducible local environment with Docker Compose for databases, MinIO, AWS/Azure/GCP emulators and WireMock, and what trade-offs it has.

Testing integrations against real services is slow, costly and sometimes dangerous. I built a repository, dev-tools, that gathers in one place everything needed to set up a local environment and test without depending on real services:

  • Local databases and storage with Docker Compose.
  • AWS, Azure and GCP emulators.
  • A mock server with WireMock.
  • Sample data in JSON.

This article explains the idea, how to use it and, above all, its limits.

The Problem

A typical project depends on a database, object storage, sometimes cloud services and third-party APIs. Without a consistent local environment, familiar things happen:

  • "It works on my machine", because each developer installed different versions.
  • Tests that depend on someone else's sandbox that goes down or has usage limits.
  • Real credentials on development machines, an unnecessary risk.
  • Slow onboarding: days to get the environment working.

The solution is to declare the environment as code and bring it up with one command.

Repository Structure

Each folder is independent: you only use the one you need.

dev-tools/
├── dev-infra/    # Local databases and storage
├── floci/        # AWS / Azure / GCP cloud emulators
├── wiremock/     # Mock server + Postman and Bruno collections
├── demo/         # Sample data in JSON

dev-infra: Databases and Storage

A Compose file with MinIO, PostgreSQL, MySQL, Redis, Oracle, MongoDB and SQL Server, with a development user created in each service. Credentials live in a local .env that isn't versioned; only the .env.example template is published.

floci: Cloud Emulators

Local emulators for AWS, Azure and GCP with a unified web console, using the images from the open-source Floci project. They let you develop against the S3, DynamoDB, Lambda and other service APIs without a real account or costs.

wiremock: Third-Party API Mocks

A WireMock server with an admin interface, sample stubs and Postman and Bruno collections. It's used to simulate external APIs: successful responses, errors, latencies and edge cases that are hard to trigger on the real service.

demo: Sample Data

Bilingual JSON catalogs (countries, banks, professions…) to use in seeds, mocks and tests.

How to Use It

git clone https://github.com/ifirestone/dev-tools.git
cd dev-tools

# Local credentials (not versioned)
cp dev-infra/.env.example dev-infra/.env

# Each stack is independent
docker compose -f dev-infra/docker-compose.yml up -d
docker compose -f floci/docker-compose.yml up -d
docker compose -f wiremock/docker-compose.yml up -d

The three stacks don't share ports, so they can run at the same time. To shut one down:

docker compose -f <folder>/docker-compose.yml down      # keeps data
docker compose -f <folder>/docker-compose.yml down -v   # also deletes data

An example with the AWS emulator:

export AWS_ACCESS_KEY_ID=test
export AWS_SECRET_ACCESS_KEY=test
export AWS_DEFAULT_REGION=us-east-1

aws --endpoint-url http://localhost:4566 s3 ls

Your application code only changes the endpoint. The rest of the client is the same one you'd use in the real cloud.

Why Mocks in Addition to Emulators

Emulators cover services with a public, stable API. For specific third-party APIs (a payment provider, a corporate platform) there is no emulator, and that's where WireMock helps:

  • Determinism: the response is always the same, so tests aren't brittle.
  • Error cases on demand: a 500, a timeout or a malformed response can be simulated in seconds.
  • Parallel work: you can develop the integration before having access to the provider's sandbox.
  • Explicit contract: the stubs document how you expect the third party to respond.

Trade-offs and Limits (What You Should Know)

A toolbox like this has costs, and they're worth stating:

  • Partial fidelity. An emulator doesn't replicate 100% of the real cloud's behavior: permissions, quota limits and edge cases may differ. Use it for development and quick tests, not as a substitute for testing against the real service before production.
  • Resource consumption. Oracle and SQL Server use a lot of memory. If your machine is tight, bring up only the services you need.
  • Local development only. None of this is meant for production or for exposure on a shared network. The sample credentials are public.
  • Docker access. The emulators mount /var/run/docker.sock to support services such as serverless functions, which gives them control over Docker on your machine. Remove that mount in environments where you don't need it.
  • Images tagged latest. Several services use that tag. If you need reproducibility, pin versions.
  • Apple Silicon. Some images only exist for x86_64 and run emulated; you'll see a platform warning, not an error.

What I Would Do Differently With More Time

  • Pin the versions of all images by default.
  • Add Compose profiles to bring up typical combinations (for example, "just PostgreSQL + MinIO").
  • Automate health checks to know when each service is ready.

Conclusion

  • A local environment declared as code speeds up onboarding and eliminates "it works on my machine".
  • Emulators and mocks let you test integrations without depending on third parties or exposing real credentials.
  • Use them for development, with clarity about their fidelity and security limits.

The repository is open source (MIT license). If you use it and a service is missing, contributions are welcome.