Skip to content
Phạm Nam

Search

Type a keyword to search the posts.

Go back
en

Floci: Free Local AWS Emulator Replacing LocalStack

Floci is a free, open-source local AWS emulator and LocalStack Community alternative: run S3, DynamoDB and Lambda on localhost:4566 for dev, testing and CI.

10 min read—

Illustration: Floci: Free Local AWS Emulator Replacing LocalStack

An afternoon fixing a handler — and a bill nobody wants to see

You just fixed a small handler: it takes a file from S3, writes metadata to DynamoDB, and pushes a message to SQS. The code changed by only a few dozen lines, but verifying it meant deploying to a real AWS dev environment, waiting for the pipeline, then checking which bucket, table, and queue were touched. Teammates on the same account meant one deleted test table stalled two people’s afternoon.

Team CI has the same problem: with no separate cloud account, every pull request needs credentials, quota checks, and cleanup. Some teams pick a paid emulator, only to find the needed feature behind a paywall. Floci addresses exactly this pain: a local AWS emulator, free and open source, with no cloud account or token. Point your SDK, AWS CLI, Terraform, or test suite at http://localhost:4566 and run the dev/test loop locally. One boundary must be clear: Floci emulates AWS at operation level. It is not real AWS.

What Floci is

Floci is an open-source AWS emulator written in Java, under the MIT license, for development, testing, and CI. Its main repository is floci-io/floci. As of 2026-11-04, it had approximately 29,000 GitHub stars, its latest release was 2.4.0, published on 2026-10-31, and code was still being pushed on the check date.

Usage is compact: every client needs only one endpoint, http://localhost:4566, regardless of region. In my view, set the principle up front: use Floci to verify application logic and data flows; final verification of permissions, billing, quotas, and edge cases still belongs on real AWS.

A drop-in replacement for LocalStack Community — by changing the image

What makes Floci notable is directly replacing LocalStack Community. It uses the same port 4566 and SDK/credential configuration, so migration is often just changing the image from localstack/localstack to floci/floci:latest.

Compatibility bridges are explicit: LocalStack variables translate automatically, e.g. PERSISTENCE=1 becomes FLOCI_STORAGE_MODE=persistent; init scripts in /etc/localstack/init/ run unchanged; /_localstack/init and /_localstack/health are still served. To disable this layer, set LOCALSTACK_PARITY=false. If an init script needs AWS CLI or boto3 in the image, use latest-compat.

Be direct: configuration compatibility does not mean full operation compatibility. Before migrating, check the official Services Overview at https://floci.io/floci/services/ for each service and operation you use, then rerun the full suite on a separate branch.

Floci fits developers working with S3, SQS, SNS, DynamoDB, and Lambda; DevOps/SRE teams wanting CI without a cloud account per runner; and sysadmins and homelab users learning AWS without a bill. Think carefully if your team must verify IAM policies, billing, or real AWS performance, or relies on a rare operation not in the Services Overview. Never use it for production, real sensitive data, or untrusted multi-tenant environments.

Architecture: one port, two execution paths

The Floci core, written in Quarkus/Java, is the single gateway on port 4566. It routes each request by service and operation under the AWS protocol, not one port per service. Configuration stays compact, but all services’ logs pile up in one place, so debug by filtering on service and operation.

From the gateway, requests split into two paths. First, in-process emulation: S3, SQS, SNS, DynamoDB, IAM, STS, KMS, Secrets Manager, SSM, EventBridge, Step Functions, and API Gateway have state simulated inside Floci. Second, Docker-backed — not a shallow mock: Lambda, RDS, Neptune, ElastiCache, MSK, ECS, EC2, EKS, OpenSearch, and CodeBuild run as real Docker containers via the Docker daemon, giving higher fidelity at the cost of image pulls, startup, and cleanup.

State for both paths goes through a storage layer decided by FLOCI_STORAGE_MODE. The web console sits outside the core: it starts lazily on the first request to http://localhost:4566/_floci/ui, runs as a sidecar, and requires the Docker socket. Disable it with FLOCI_SERVICES_UI_ENABLED if unneeded.

flowchart TD
    A["Client: AWS CLI, SDK, Terraform/CDK, Testcontainers"]
    B["Single endpoint localhost:4566"]
    C["Floci core Quarkus/Java: routing by service/operation"]
    D["In-process emulation: S3, SQS, SNS, DynamoDB, IAM/STS, KMS, Secrets Manager, SSM"]
    E["Docker-backed: Lambda, RDS, ECS, EC2, EKS, ElastiCache, MSK, OpenSearch via Docker daemon"]
    F["Storage layer: memory / persistent / hybrid flush 5s / wal"]
    G["Optional console sidecar: _floci/ui, lazy start, requires Docker socket"]
    H["Account partitioning: 12-digit key becomes account ID, otherwise falls back to 000000000000"]
    I["This is not real AWS: IAM, billing and unsupported operations are not verified here"]
    A --> B --> C
    C --> D
    C --> E
    D --> F
    E --> F
    C --> G
    C --> H
    C -.-> I
    classDef dashed stroke-dasharray: 5 5
    class I dashed

Storage and multi-account behaviour

FLOCI_STORAGE_MODE has four modes. The wrong mode is a common reason a test passes today, loses data tomorrow, or runs slowly for no obvious reason.

  • memory: RAM only, lost on stop. Suits CI: fast, clean reset.
  • persistent: written to disk on every write. More durable, but pays a disk write per change.
  • hybrid: RAM plus async flush every 5 seconds. Suits local development, accepting up to 5 seconds of data loss.
  • wal: write-ahead log, the most durable of the four.

In my view: CI uses memory; local development uses hybrid or persistent by acceptable data loss; data surviving a restart never uses memory.

Multi-account behaviour: if AWS_ACCESS_KEY_ID is exactly 12 digits, Floci uses it as the account ID and isolates resources per account. Otherwise it falls back to FLOCI_DEFAULT_ACCOUNT_ID, default 000000000000. So every job sharing a test credential such as test shares one default account and can collide on buckets, tables, and queues. For parallel tests, give each job its own 12-digit key. This is test-data partitioning, not a security boundary.

Deployment with Docker Compose

You need Docker Engine with the Compose plugin, port 4566 free, and the AWS CLI or your language’s SDK. In my view, pin floci/floci:2.4.0 for CI and this guide for reproducibility. The -baseline tag is only for ARM64, such as Raspberry Pi 4.

Create a docker-compose.yml file, run it, and wait for the Ready. log line:

services:
  floci:
    image: floci/floci:2.4.0
    ports:
      - "4566:4566"
docker compose up -d
docker compose logs -f floci
export AWS_ENDPOINT_URL=http://localhost:4566
export AWS_DEFAULT_REGION=us-east-1
export AWS_ACCESS_KEY_ID=test
export AWS_SECRET_ACCESS_KEY=test

See also Dockge for managing Compose stacks via a web interface, and Coolify for moving a lab onto your own server.

Alternative path, briefly: the official CLI flow is floci start followed by eval $(floci env), from the separate repository floci-io/floci-cli, and each release ships a native floci-aws binary for Linux, macOS, and Windows. CLI install commands beyond that flow are not covered here; Docker Compose is the primary path.

Verification and common errors

The commands below are copied from the official Quick Start; they are not results I ran myself. Expected behaviour: bucket and table creation succeed, and listing shows the new table. An unsupported-operation error signals checking the Services Overview, not automatically a configuration error.

aws s3 mb s3://my-bucket
aws dynamodb create-table --table-name demo-table \
  --attribute-definitions AttributeName=pk,AttributeType=S \
  --key-schema AttributeName=pk,KeyType=HASH \
  --billing-mode PAY_PER_REQUEST
aws dynamodb list-tables

Pros and cons

The clearest advantage: completely free — no cloud account, no token, no feature paywall. Next is the drop-in LocalStack Community replacement: change the image and it runs, keeping the same port, credentials, SDK setup, and most init scripts. Coverage suits everyday needs, from S3, SQS, SNS, DynamoDB, Lambda, IAM/STS, KMS, Secrets Manager, SSM, EventBridge, Step Functions, and API Gateway through to Bedrock and SageMaker at operation level. Docker-backed services offer higher fidelity than shallow mocks for Lambda, RDS, ECS, EC2, EKS, and data services.

Plainly, the disadvantages: this is not real AWS — compatibility is operation-level, and a local pass does not prove a real AWS pass. IAM/STS accepts arbitrary credentials by default, so it cannot verify real policies or permission errors. Docker-backed services are heavier, depend on the Docker daemon, and need image pulls. The console is a sidecar outside the core, needs the Docker socket, and has its own image version, 0.7.0, so it can drift from the core. The community is younger than a long-established rival: the repository was created in February 2026, though developing very fast.

On performance, no benchmark was measured for this article, so no speed figures are given — only documented configuration trade-offs: memory fastest but volatile; persistent durable but writes to disk each time; hybrid balanced with a 5-second loss window; wal most durable via write-ahead logging. On operations, the Ready. log line signals startup, /_localstack/health keeps old health-check compatibility, and rollback is simple: revert the Compose image to localstack/localstack or an older Floci tag, restore old variables and init scripts, and rerun the S3 and DynamoDB smoke tests.

Security considerations

Run it only on localhost, never expose port 4566 to the network, and never use it for production data or real credentials. The endpoint is local HTTP with default test/test credentials, so exposing it is effectively opening a fake AWS with no authentication. Do not mount the Docker socket unless you need the console or a Docker-backed service — it is equivalent to Docker host control if the container is compromised.

Comparison with alternatives in the same scope

Criteria are uniform: price and paywall; operation-level coverage; fidelity; storage; multi-account behaviour; SDK, CLI, Terraform, and Testcontainers compatibility; and maturity. Unverified cells are marked as such, not filled in for completeness.

CriterionFlociLocalStackMoto and library mocksReal AWS (sandbox)
PriceFree, no paywallCommunity free, paid tiers existFree as a libraryCosts money
ModelServer emulator over HTTP, port 4566Server emulator over HTTP, port 4566Mock embedded in test codeReal cloud
FidelityPure emulation plus Docker-backedLong-established emulator, check operations individuallyFast for unit testsGold standard for IAM, billing, quota
Multi-language CIGood, one endpointGood, same modelLimited by languageGood, but needs credentials and cleanup

Versus LocalStack, Floci fits when you hit a paywall or need Docker-backed services; stay on LocalStack if your suite is already stable there or your team pays for Pro. Versus Moto, the difference is model: Moto is embedded in test code, while Floci is an independent HTTP server, serving every language, SDK, Terraform, and CDK. Versus real AWS, real AWS remains the gold standard for IAM, billing, quota, and edge behaviour, but costs money and needs cleanup — use Floci for the frequent dev/test and CI loop, and real AWS in a separate sandbox for final verification. AI warning: Bedrock and SageMaker in Floci are only operation- and API-level emulations, not real model execution.

Real use cases

  • CI without a cloud account: each pull request runs Floci in memory mode, tests touch S3, DynamoDB, and SQS locally, then it is discarded. Check the operation matrix first; keep IAM tests in an AWS sandbox.
  • Homelab and self-learners: learn S3, DynamoDB, Lambda, and IAM with Docker Compose, without a cloud account. A local lab cannot teach real billing, quotas, or network failures.
  • AI workflows: upload to S3, trigger Lambda, push through SQS, orchestrate with Step Functions and EventBridge, and write metadata to DynamoDB — without calling real Bedrock.
  • DevOps/SRE, Terraform, CDK, Testcontainers: point Terraform, CDK, or OpenTofu at localhost:4566 to test plan, apply, and destroy without touching the cloud; give parallel jobs their own 12-digit keys.
  • IT admins, drills and training: rehearse S3 backup/restore, secret rotation via Secrets Manager and SSM, and queue congestion — restarting in memory mode gives a clean environment.

Troubleshooting

Port 4566 taken: change the mapping or stop the old process. Docker not running or Compose plugin missing: Floci cannot start — check Docker first. Console not opening: usually a missing Docker socket mount or the floci-ui sidecar not pulled; disable the console if unneeded. Old LocalStack init script failing: switch to latest-compat and check /etc/localstack/init/. Parallel tests colliding: usually shared test credentials falling back to the default account. Unsupported operation: check the Services Overview, then mock it separately, drop that test locally, or verify on real AWS.

Conclusion

Floci fits teams paying for a slow, expensive AWS test loop, teams that hit another emulator’s paywall, CI setups needing a fast-reset clean environment, and homelabs learning AWS for free. It does not fit teams verifying IAM policies, billing, quotas, and real performance; workloads depending on rare operations; untrusted multi-tenant environments; or production.

Next steps: run Compose with pinned 2.4.0; run the three S3 and DynamoDB commands above; check the Services Overview for exactly your services; and if on LocalStack, migrate on a separate branch and rerun the suite before deleting old configuration. Floci is worth trying because it removes the cost and paywall bottleneck of local AWS testing — but only if the team respects the emulator’s boundary and keeps a real AWS verification loop.

Lessons learned

  1. Configuration compatibility is not operation compatibility — rerun the test matrix after an image swap.
  2. A shared test credential is a shared account — parallel tests need their own 12-digit keys.
  3. Storage mode is an operational decision — memory for CI; hybrid, persistent, or wal for development, by acceptable data loss.
  4. Docker-backed services and pure mocks have different costs — do not merge their CI times into one number.
  5. A local test pass does not prove IAM is correct — keep a real AWS sandbox loop for permissions.
  6. The console is convenient but expensive in privileges — do not mount the Docker socket when unneeded.

Verification scope

Check date: 2026-11-04, cross-checked against official documentation and the GitHub API for floci-io/floci. Verified: repository, MIT license, Java, approximate stars/forks, release 2.4.0 dated 2026-10-31, the Compose file, environment variables, port 4566, sample AWS CLI commands, the storage-mode table, the 12-digit key mechanism, and the LocalStack mapping. Default versus opt-in versus schema-only: endpoint 4566 and test credentials are defaults; storage mode, LOCALSTACK_PARITY=false, and disabling the console are options; the service list is operation-level scope per the Services Overview, not full parity. Numbers are configuration, not benchmarks: hybrid flush every 5 seconds, ports 4566 and 4500, default account 000000000000. Not tested: Floci was not installed, run, or benchmarked; individual Services Overview operations were not verified; CLI install commands beyond floci start and eval $(floci env) were not verified; star counts are approximate and change daily.

References


Related posts

Bình luận

Bình luận được duyệt trước khi hiển thị.

Đang tải bình luận…

Để lại bình luận