Back to blog
October 9, 2026•39 views

Local Cloud Emulators Compared: LocalStack, SAM Local, and Firebase

localstackaws sam localfirebase emulator suitelocal cloud testingaws emulatorintegration testingdockerci cd
Local Cloud Emulators Compared: LocalStack, SAM Local, and Firebase

I have lost more hours to cloud sandbox setup than I care to admit. Spin up a fresh AWS account, wire IAM roles, wait for a queue to propagate, burn through free tier credits because a Lambda looped, then realize the bug was in my own retry logic. That cycle is exactly why local cloud emulators went from a niche DevOps trick to something I now install on day one of almost every project.

This piece is a working comparison, not a sponsored tour. I run a Next.js and Node stack, I ship automation platforms, and I have used these tools on client work across several regions and time zones. So the opinions below come with scar tissue attached.

Disclosure on Fakecloud: I could not verify Fakecloud. There is no canonical public project page, no published image on a major registry, and no stable feature list I was able to confirm at the time of writing. Because of that, I have removed Fakecloud from the comparison table below and I do not make any verified claims about it. If you arrived here searching for "Fakecloud vs LocalStack," the honest answer is that I cannot give you a verified comparison. What I can give you is a real comparison of the emulators I have actually run: LocalStack, AWS SAM Local, and the Firebase Emulator Suite.

What local cloud emulators actually are (and what they are not)

A local cloud emulator is a process, usually Dockerized, that speaks the same HTTP API as a real cloud provider. Your AWS SDK points at http://localhost:4566 instead of https://sqs.us-east-1.amazonaws.com, and the code path stays identical.

That last part matters. If you have to change your application code to run locally, you are not emulating, you are mocking. Mocks are fine for unit tests. They are useless for catching the class of bug that only shows up when an SQS message gets redelivered or a DynamoDB conditional write fails.

What emulators are not:

  • They are not a replacement for a staging environment against real cloud services.
  • They are not guaranteed to match provider behavior byte for byte.
  • They are not free of operational cost. Someone still has to maintain the thing.

I treat them as a fast inner loop, not as the final gate before production.

LocalStack vs SAM Local vs Firebase Emulator Suite

Here is how I would score the three emulators I have actually run for a typical Node or Next.js backend. Startup times below are rough wall-clock numbers I have observed on a 16GB M-series MacBook with Docker Desktop, warm image cache, and no other heavy containers running. Treat them as directional, not benchmarks. Note that the three tools measure different things: LocalStack's number is per-session startup (the whole emulator comes up once and stays up), while SAM Local's number is per-invocation (each sam local invoke spins up a container for a single function run). Firebase sits closer to per-session, since firebase emulators:start boots the suite once.

Dimension LocalStack AWS SAM Local Firebase Emulator Suite
Primary cloud AWS (plus some others) AWS Google / Firebase
Startup time (observed) ~15-30s per session ~5-10s per invocation ~3-5s per session
Service breadth Very broad Lambda, API Gateway, plus DynamoDB Local Firebase products only
Resource footprint Heavier (often 1-2GB RAM) Light Moderate
IaC integration Strong (Terraform, CDK, CloudFormation) CloudFormation native Limited
License model Open core, paid Pro tier Open source Open source
Best for Full app emulation Serverless-first teams Mobile and web apps
Learning curve Medium Medium Low

Read that table as a starting position, not gospel. Service coverage changes month to month in this space, and any comparison post older than a few months is probably stale. Check the project changelogs before you commit.

One clarification that trips people up: DynamoDB Local is a separate tool from SAM Local. SAM Local can run your Lambda functions and API Gateway locally and it can talk to DynamoDB Local, but it does not bundle or start DynamoDB Local for you. You install and run DynamoDB Local on its own (usually as another container or a Java process), then point your SDK at its endpoint. If your handler needs a table, that is a second thing to start, not a flag on sam local invoke.

Where LocalStack earns its place

The moment your architecture includes Step Functions, EventBridge rules, Kinesis, or anything with real orchestration, LocalStack's coverage becomes hard to argue with. I have had lighter setups fall over because a service simply was not implemented, and then I am back to installing LocalStack anyway. The startup cost is real, but it is a one-time cost per session, not per test.

LocalStack Pro also gives you things the free tier does not, and yes, it costs money. I have paid for it on projects where the alternative was burning real AWS spend on integration tests. That is a business decision, not a religious one. If your tests would otherwise cost more than the license, buy the license.

One practical note for recent versions: newer LocalStack releases expect an auth token even for some community usage paths, configured via the LOCALSTACK_AUTH_TOKEN environment variable. If you pull a recent image and the container exits or logs an auth warning, check the current docs for your version and set the token rather than assuming the image is broken.

Where SAM Local fits

If you are serverless-first and already define your stack in template.yaml, SAM Local is the lowest-friction option. sam local invoke runs a single function against a local container in seconds, which is perfect for tight iteration on a handler. To be precise about what it is: SAM Local is a local invoke and run tool, not a full cloud emulator. It does not stand up a persistent, API-compatible version of AWS the way LocalStack does. It covers Lambda and API Gateway, and it can talk to DynamoDB Local if you run that separately, but you will still reach for LocalStack when you need SQS, SNS, or Step Functions.

A minimal setup looks like this:

# Install the SAM CLI (macOS via Homebrew)
brew install aws-sam-cli

# Invoke a single function defined in template.yaml with a test event
sam local invoke MyFunction --event events/test.json

# Or run the whole API locally on port 3000
sam local start-api

Where the Firebase Emulator Suite fits

For Firebase projects, the emulator suite is the strongest option I have used, and I have not found anything that covers its surface as cleanly. Firestore, Auth, Functions, Storage, and Hosting all run locally with a single firebase emulators:start. If your stack is Firebase, this is likely the right tool and the rest of this article is mostly about AWS.

A minimal setup:

# Install the Firebase CLI
npm install -g firebase-tools

# Log in once, then start the emulator suite
firebase login
firebase emulators:start

Setting up a local cloud emulator without losing a day

The setup is the part every comparison post skips. Here is the shape that works for me, using LocalStack's actual published image. Note the pinned tag: localstack/localstack:3 is a major-version pin, and for CI I would go tighter still, for example localstack/localstack:3.7.2, so a new patch release cannot change behavior under you overnight.

# Pull and run a pinned LocalStack image
docker run -d \
  --name localstack \
  -p 4566:4566 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  localstack/localstack:3

# Verify it responds
curl -s http://localhost:4566/_localstack/health

Then point your SDK at it with environment variables rather than code changes. The AWS_ENDPOINT_URL variable is the standard way to redirect AWS SDKs, and it is supported across the AWS SDKs. Check your SDK version, though: AWS_ENDPOINT_URL support landed in relatively recent releases. As a rough guide, you want AWS SDK for JavaScript v3.398 or later, boto3 1.28 or later, and the AWS CLI v2.13 or later. On older SDKs you will need to pass the endpoint explicitly in client config instead.

export AWS_ENDPOINT_URL=http://localhost:4566
export AWS_ACCESS_KEY_ID=test
export AWS_SECRET_ACCESS_KEY=test
export AWS_REGION=us-east-1

In a Node or Next.js project, that means your S3Client config reads the endpoint from the environment and nothing else changes. Server routes, background workers, and scripts all inherit the same behavior.

A few non-negotiables I have learned the hard way:

  1. Never hardcode the endpoint in application code. Environment only.
  2. Use a docker-compose.yml so the emulator starts with the rest of your stack.
  3. Seed your emulator with the same resources your IaC defines, otherwise local and cloud drift immediately.
  4. Add a health check to your compose file. Tests that race the emulator startup produce the flakiest failures you will ever debug.

Here is a compose file with a pinned image and a health check:

services:
  localstack:
    image: localstack/localstack:3.7.2
    ports:
      - "127.0.0.1:4566:4566"
    environment:
      - LOCALSTACK_AUTH_TOKEN=${LOCALSTACK_AUTH_TOKEN:-}
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
    healthcheck:
      test: ["CMD", "curl", "-sf", "http://localhost:4566/_localstack/health"]
      interval: 5s
      timeout: 3s
      retries: 10

Wiring emulators into CI/CD

This is where local cloud testing pays for itself. Running integration tests against a real cloud account in CI is slow, costs money per run, and occasionally leaks credentials into logs. An emulator removes all three problems.

A minimal GitHub Actions job looks like this. Service containers in GitHub Actions do not reliably honor a healthcheck block the way Compose does, so do not count on the platform waiting for readiness for you. The dependable pattern is to poll the endpoint in a step before running tests.

name: integration
on: [push]
jobs:
  test:
    runs-on: ubuntu-latest
    services:
      localstack:
        image: localstack/localstack:3.7.2
        ports:
          - 4566:4566
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      - name: Wait for emulator
        run: |
          for i in $(seq 1 30); do
            curl -sf http://localhost:4566/_localstack/health && break
            sleep 2
          done
      - run: npm run test:integration
        env:
          AWS_ENDPOINT_URL: http://localhost:4566
          AWS_ACCESS_KEY_ID: test
          AWS_SECRET_ACCESS_KEY: test
          AWS_REGION: us-east-1

Two things to watch. First, the emulator needs to be ready before your tests start, so add an explicit readiness poll rather than assuming the container is up. Second, keep your integration suite separate from your unit suite. Integration tests are slower and you do not want them blocking every commit if the team is large.

Common pitfalls that will bite you

Emulators are not the real cloud, and pretending otherwise causes pain. Here is what I have run into most often.

  • Service parity gaps. A service exists but a specific API action does not. Your code works locally and 500s in production. Test the actions you actually use, not just the service name.
  • Networking weirdness. Lambda inside an emulator talking to another container is not the same as Lambda in a VPC. Timeouts behave differently.
  • Data persistence. Some emulators wipe state on restart, some do not. Know which one you have, or your test suite will pass in a random order and fail in another.
  • IAM is often a no-op. If the emulator does not enforce permissions, you will never catch a missing policy until deploy day. Run at least one staging pass against real IAM.
  • Version drift. The emulator tracks a provider API version. Pin the image tag. latest will eventually break your pipeline on a Tuesday morning.

Security notes people skip

A local emulator running on a developer laptop is not a security boundary. If you are loading production data into it, you have effectively copied production data onto an unmanaged device. I have seen this happen on more than one team.

A few rules I enforce:

  • Never seed emulators with real customer data. Generate synthetic fixtures.
  • Use obviously fake credentials (test/test) so a misconfigured SDK fails loudly against real AWS.
  • Bind the emulator to 127.0.0.1, not 0.0.0.0, unless you genuinely need it reachable from another container.
  • Treat emulator config files as code. Review them.

When to skip emulators entirely

I do not use them everywhere. There are cases where the overhead is not worth it.

  • Simple CRUD apps where the cloud surface is one database. Just use a local Postgres.
  • Projects where the team is small and staging deploys are cheap. The emulator becomes a toy nobody maintains.
  • Anything heavily reliant on managed services with no emulation support. You will spend more time working around gaps than you save.

The decision is really about feedback loop speed versus fidelity. If your loop is already fast, adding an emulator does not help.

My recommendation

If you are building serverless or event-driven systems on AWS, install a local cloud emulator today. Start with SAM Local if you are serverless-first, or LocalStack if you need orchestration and IaC depth. Keep your integration tests honest by running them against real cloud services at least once before release.

The teams I have seen ship fastest treat the emulator as a tool, not a religion. They know exactly which behaviors it fakes well and which ones it fakes badly, and they plan their testing around that. Pick the one that matches your stack, pin your versions, and revisit the choice when your architecture changes.

Frequently asked questions

Is Fakecloud a drop-in replacement for LocalStack?

I could not verify Fakecloud. There is no canonical public project page, published container image, or stable feature list I was able to confirm at the time of writing, so I cannot give you a verified comparison. If you need a LocalStack alternative today, the well-documented options are AWS SAM Local (for serverless-first AWS teams) and the Firebase Emulator Suite (for Firebase projects). Verify any lesser-known tool against its own repository and changelog before building on it.

Are local cloud emulators safe for testing with production data?

No. An emulator is not a security boundary. Loading real customer data into a local emulator means that data now lives on an unmanaged device. Use synthetic fixtures, fake credentials, and bind the emulator to localhost only.

Do local cloud emulators work for Google Cloud and Azure?

Coverage is thinner than AWS. Google offers official emulators for Pub/Sub, Firestore, and Cloud Functions, and the Firebase Emulator Suite is the strongest option for Firebase projects. Azure's story is more fragmented. For GCP and Azure, expect to rely more on real staging environments than on emulators.

Can I run integration tests against an emulator in CI?

Yes, and it is one of the best use cases. Run the emulator as a service container in GitHub Actions or GitLab CI, point your SDK at its endpoint via environment variables, and keep the integration suite separate from unit tests. Add an explicit readiness poll so tests do not race the emulator startup, since service containers do not reliably honor healthcheck blocks.

Share this post

Native Web Share is available on mobile — that share sheet includes Instagram and any other app you have installed.

Let's Connect

Get In Touch

Let's build something premium together.

Contact info

Follow me
Chat on WhatsApp