Skip to content
cloudemu

§ Documentation

Quick Start

Run cloudemu as a server and point your real app at it in 5 minutes

cloudemu is a real cloud emulator: it speaks the actual AWS, Azure, and GCP wire protocols, so you point real SDK clients, CLIs, and apps at it and run production code unchanged.

The fastest way to integrate it is server mode: run the binary (or Docker image) and set your SDK's endpoint at the printed address. Your already-running app now talks to an in-memory cloud over the real wire — the same code path it uses in production. This is the default for integration and end-to-end work.

No mocks. No cloud accounts. No bills — just a running endpoint your code already knows how to talk to.

Install#

go install github.com/stackshy/cloudemu/v2/cmd/cloudemu@latest

No Go toolchain? Use the published Docker image instead — see Run the server.

Run the server#

cloudemu serve

On start it prints the live endpoints:

cloudemu — standalone server
────────────────────────────
  AWS         http://127.0.0.1:4566
  Azure       https://127.0.0.1:4568   (self-signed TLS)
  GCP         http://127.0.0.1:4569
  Kubernetes  http://127.0.0.1:4570

Or with Docker, no Go required:

docker run --rm -p 4566:4566 -p 4568:4568 -p 4569:4569 ghcr.io/stackshy/cloudemu:latest

Point your app at it#

The only thing that changes vs. real AWS is the endpoint. Every other line of your production code stays identical. For the AWS CLI and any language's SDK, the AWS_ENDPOINT_URL env var is enough:

export AWS_ENDPOINT_URL=http://127.0.0.1:4566
aws s3 mb s3://app-deployments          # your real CLI, unchanged
aws s3 cp ./config.yaml s3://app-deployments/v1.0/config.yaml

In aws-sdk-go-v2, override BaseEndpoint where your app builds its client:

client.go — where your app builds its client
client := s3.NewFromConfig(cfg, func(o *s3.Options) {
    o.BaseEndpoint = aws.String("http://127.0.0.1:4566")
    o.UsePathStyle = true
})

// ↓ This is your real production code, unchanged. ↓
client.CreateBucket(ctx, &s3.CreateBucketInput{Bucket: aws.String("app-deployments")})

Done. Real server, real SDK, in-memory backend, ~10 ms per call.

What just happened#

Your codereal aws-sdk-go-v2HTTPWire protocolS3 REST · JSON-RPC · CBORcloudemuin-memory
one request, end to end — ~10ms
FIG.The request path — a real SDK call into the in-memory backend and back.

The server speaks the actual AWS wire protocol (S3 REST + XML, DynamoDB JSON-RPC, EC2 query, SQS AwsJson1_0, CloudWatch Smithy CBOR, Lambda REST). The SDK can't tell the difference between this and s3.amazonaws.com.

The endpoint override, every SDK#

The endpoint override is the only change your app needs. Point your provider's client at the matching port — the tabs below stay in sync across the site, so pick your provider once.

aws
// Any language / the CLI: set AWS_ENDPOINT_URL=http://127.0.0.1:4566
client := s3.NewFromConfig(cfg, func(o *s3.Options) {
    o.BaseEndpoint = aws.String("http://127.0.0.1:4566")
    o.UsePathStyle = true
})
// Any credentials work — cloudemu doesn't validate signatures.

See Standalone Server for ports, flags, cloudemu env, Testcontainers, and the /_cloudemu/reset control plane; and Integrating cloudemu to make the endpoint injectable so the same code hits real cloud in prod and cloudemu in tests.

Library mode — Go unit tests only#

If you're writing unit tests inside Go code that imports cloudemu, you can skip the separate process and stand the server up in-process with httptest. Use this only for unit tests — for integrating an existing service, prefer server mode above.

something_test.go
cloud := cloudemu.NewAWS()
ts := httptest.NewServer(awsserver.New(awsserver.Drivers{
    S3: cloud.S3, DynamoDB: cloud.DynamoDB, EC2: cloud.EC2,
    Lambda: cloud.Lambda, SQS: cloud.SQS, CloudWatch: cloud.CloudWatch,
}))
defer ts.Close()

client := s3.NewFromConfig(cfg, func(o *s3.Options) {
    o.BaseEndpoint = aws.String(ts.URL) // same override, in-process URL
    o.UsePathStyle = true
})

The Portable Go API goes one step further — call the in-memory drivers directly, no HTTP at all.

SDK-compat coverage#

Every domain ships HTTP wire-format handlers across all 3 providers:

DomainAWSAzureGCP
StorageS3BlobGCS
ComputeEC2 + full VPC stackVirtual Machines + Disks/Snapshots/ImagesCompute Engine + Disks/Snapshots/Images
Database (NoSQL)DynamoDBCosmos DBFirestore
Relational DBRDS + RedshiftSQL + Postgres/MySQL FlexCloud SQL
Networking(in EC2)VNetVPC + Firewalls
MonitoringCloudWatchAzure MonitorCloud Monitoring
ServerlessLambdaFunctionsCloud Functions
KubernetesEKSAKSGKE
Message QueueSQSService BusPub/Sub
LoggingCloudWatch LogsLog AnalyticsCloud Logging
DNSRoute 53Azure DNSCloud DNS
Load BalancerELBv2Load BalancerCloud Load Balancing
CacheElastiCacheAzure CacheMemorystore
SecretsSecrets ManagerKey VaultSecret Manager
NotificationSNSNotification HubsFCM
Event BusEventBridgeEvent GridEventarc
IAMIAMIAMIAM
Container RegistryECRACRArtifact Registry
Resource DiscoveryResource Explorer + TaggingResource GraphCloud Asset Inventory

Plus provider-specific Generative AI (Bedrock + SageMaker on AWS, Vertex AI on GCP) and Databricks (Azure). Kubernetes also ships a shared in-memory data plane that client-go / kubectl drive end-to-end.

Everything is equally reachable through the Portable Go API when you'd rather skip HTTP.

Next steps#

On this page

On this page