Star 历史趋势
数据来源: GitHub API · 生成自 Stargazers.cn
README.md

Floci

Latest Release Build Status Docker Pulls Docker Image Size License: MIT GitHub Stars GitHub Contributors Join Floci on Slack

Named after floccus — the cloud formation that looks exactly like popcorn.

A free, open-source local AWS emulator. No account. No feature gates. Just docker compose up.

Join the community on Slack to ask questions, share feedback, and discuss Floci with other contributors and users. You can also open any topic in GitHub Discussions — feature ideas, compatibility questions, design tradeoffs, wild proposals, or half-baked thoughts are all welcome. No idea is too small, too early, or too popcorn-fueled to start a good discussion.


[!IMPORTANT] Image moved to floci/floci. Update your docker-compose.yml and docker run commands:

# Before
image: hectorvent/floci:latest
# After
image: floci/floci:latest

The old hectorvent/floci repository will no longer receive updates.


LocalStack's community edition sunset in March 2026 — requiring auth tokens, and freezing security updates. Floci is the no-strings-attached alternative.

Why Floci?

FlociLocalStack Community
Auth token requiredNoYes (since March 2026)
Security updatesYesFrozen
Startup time~24 ms~3.3 s
Idle memory~13 MiB~143 MiB
Docker image size~90 MB~1.0 GB
LicenseMITRestricted
API Gateway v2 / HTTP API
Cognito
ElastiCache (Redis + IAM auth)
RDS (PostgreSQL + MySQL + IAM auth)
MSK (Kafka + Redpanda)
Athena (real SQL via DuckDB sidecar + Glue views)
Glue Data Catalog + Schema Registry
Data Firehose (NDJSON delivery)
S3 Object Lock (COMPLIANCE / GOVERNANCE)⚠️ Partial
DynamoDB Streams⚠️ Partial
IAM (users, roles, policies, groups)⚠️ Partial
STS (all 7 operations)⚠️ Partial
Kinesis (streams, shards, fan-out)⚠️ Partial
KMS (sign, verify, re-encrypt)⚠️ Partial
ECS (clusters, services, tasks)
EKS (clusters, mock + real k3s)
EC2 (real Docker instances, IMDS, SSH, UserData)
CodeBuild (real Docker build execution, S3 artifacts, CloudWatch logs)
CodeDeploy (Lambda traffic shifting, lifecycle hooks, auto-rollback)
Auto Scaling (groups, launch configs, reconciler, ELB v2 integration)
SSM Run Command (SendCommand + real agent polling via ec2messages)
Transfer Family (SFTP server management, users, SSH keys)
Native binary✅ ~40 MB

Broad AWS coverage. Free forever.

Migrating from LocalStack

Floci is a drop-in replacement for LocalStack Community. The port (4566), credentials, and all AWS SDK and CLI calls work unchanged — swap the image and you're done.

# Before image: localstack/localstack # After — no init scripts, or scripts that don't call aws / boto3 image: floci/floci:latest # After — init scripts that use aws CLI or boto3 image: floci/floci:latest-compat # includes Python 3, AWS CLI, boto3 pre-configured

LocalStack environment variables are translated automatically — no renaming required:

LocalStackFloci equivalent
LOCALSTACK_HOSTFLOCI_HOSTNAME
PERSISTENCE=1FLOCI_STORAGE_MODE=persistent
LAMBDA_DOCKER_NETWORKFLOCI_SERVICES_LAMBDA_DOCKER_NETWORK
LAMBDA_REMOVE_CONTAINERS=1FLOCI_SERVICES_LAMBDA_EPHEMERAL=true
DEBUG=1QUARKUS_LOG_LEVEL=DEBUG

Init scripts mounted under /etc/localstack/init/ run unchanged. The /_localstack/init and /_localstack/health endpoints are still served. Set LOCALSTACK_PARITY=false to opt out of the automatic translation.

Full migration guide

Architecture Overview

flowchart LR Client["☁️ AWS SDK / CLI"] subgraph Floci ["Floci — port 4566"] Router["HTTP Router\n(JAX-RS / Vert.x)"] subgraph Stateless ["Stateless Services"] A["SSM · SQS · SNS\nIAM · STS · KMS\nSecrets Manager · SES\nCognito · Kinesis\nEventBridge · Scheduler · AppConfig\nCloudWatch · Step Functions\nCloudFormation · ACM\nAPI Gateway · ELB v2 · Auto Scaling\nCodeDeploy · Backup · Bedrock Runtime · Route53 · Transfer"] end subgraph Stateful ["Stateful Services"] B["S3 · DynamoDB\nDynamoDB Streams"] end subgraph Containers ["Container Services 🐳"] C["Lambda\nElastiCache\nRDS\nECS\nEC2\nMSK\nEKS\nOpenSearch\nCodeBuild"] D["Athena ➜ floci-duck\n(DuckDB sidecar)"] end Router --> Stateless Router --> Stateful Router --> Containers Stateless & Stateful --> Store[("StorageBackend\nmemory · hybrid\npersistent · wal")] end Docker["🐳 Docker Engine"] Client -->|"HTTP :4566\nAWS wire protocol"| Router Containers -->|"Docker API\n+ IAM / SigV4 auth"| Docker

Real Docker Integration

Unlike mock-only emulators, Floci runs real Docker containers for services where in-process emulation would compromise fidelity — stateful databases, connection-heavy protocols, and runtimes that require native execution. The result is wire-compatible behavior against the actual engine, not a simplified approximation.

ServiceDefault Docker imageWhat's real
Lambdapublic.ecr.aws/lambda/<runtime>AWS runtime environment, execution model, warm container pool
ElastiCachevalkey/valkey:8Full Redis/Valkey protocol, ACL-based IAM auth, SigV4 validation
RDS (PostgreSQL)postgres:16-alpineReal PostgreSQL engine, IAM auth via token, JDBC-compatible
RDS (MySQL / Aurora)mysql:8.0Real MySQL engine, IAM auth, JDBC-compatible
RDS (MariaDB)mariadb:11Real MariaDB engine, IAM auth, JDBC-compatible
MSKredpandadata/redpanda:latestReal Kafka-compatible broker via Redpanda
EC2AMI-mapped (e.g. public.ecr.aws/amazonlinux/amazonlinux:2023)Real Linux containers; SSH key injection; UserData execution; IMDS with IMDSv1+IMDSv2 and IAM credential serving
ECSUser-specified in task definitionActual container lifecycle — start, stop, health checks
EKSrancher/k3s:latestLive Kubernetes API server (k3s), full kubeconfig
CodeBuildUser-specified environment image (e.g. public.ecr.aws/codebuild/amazonlinux2-x86_64-standard:5.0)Real buildspec execution — install/pre_build/build/post_build phases in container; S3 artifact upload; CloudWatch log streaming
OpenSearchopensearchproject/opensearch:2Full OpenSearch engine with REST API
ECRregistry:2Real OCI-compatible registry — docker push / docker pull work natively

Lambda runtimes

Floci resolves each Lambda runtime to the corresponding AWS public ECR image:

RuntimeImage
java25 · java21 · java17 · java11 · java8.al2 · java8public.ecr.aws/lambda/java:<version>
python3.14 · python3.13 · python3.12 · python3.11 · python3.10 · python3.9public.ecr.aws/lambda/python:<version>
nodejs24.x · nodejs22.x · nodejs20.x · nodejs18.x · nodejs16.xpublic.ecr.aws/lambda/nodejs:<version>
ruby3.4 · ruby3.3 · ruby3.2public.ecr.aws/lambda/ruby:<version>
dotnet10 · dotnet9 · dotnet8 · dotnet6public.ecr.aws/lambda/dotnet:<version>
go1.xpublic.ecr.aws/lambda/go:1
provided.al2023 · provided.al2 · providedpublic.ecr.aws/lambda/provided:<variant>

Container image functions (package type Image) pass the ImageUri through directly, with ECR repository URIs rewritten to the local Floci ECR endpoint automatically.

Requirements

Docker-backed services require the Docker socket to be accessible:

docker run -d --name floci \ -p 4566:4566 \ -v /var/run/docker.sock:/var/run/docker.sock \ -u root \ floci/floci:latest

In Docker Compose, add the socket volume alongside any other mounts.

Overriding default images

All default images are configurable via environment variables, useful for pinning versions or using a local mirror:

VariableDefault
FLOCI_SERVICES_ELASTICACHE_DEFAULT_IMAGEvalkey/valkey:8
FLOCI_SERVICES_RDS_DEFAULT_POSTGRES_IMAGEpostgres:16-alpine
FLOCI_SERVICES_RDS_DEFAULT_MYSQL_IMAGEmysql:8.0
FLOCI_SERVICES_RDS_DEFAULT_MARIADB_IMAGEmariadb:11
FLOCI_SERVICES_MSK_DEFAULT_IMAGEredpandadata/redpanda:latest
FLOCI_SERVICES_OPENSEARCH_DEFAULT_IMAGEopensearchproject/opensearch:2
FLOCI_SERVICES_EKS_DEFAULT_IMAGErancher/k3s:latest
FLOCI_SERVICES_ECR_REGISTRY_IMAGEregistry:2
FLOCI_ECR_BASE_URIpublic.ecr.aws (Lambda runtime base)

Supported Services

ServiceHow it worksNotable features
SSM Parameter StoreIn-processVersion history, labels, SecureString, tagging
SSM Run CommandIn-processSendCommand, GetCommandInvocation, ListCommands, CancelCommand; DescribeInstanceInformation; ec2messages polling protocol so the real amazon-ssm-agent running inside EC2 containers can register, receive commands, and report output
SQSIn-processStandard & FIFO, DLQ, visibility timeout, batch, tagging
SNSIn-processTopics, subscriptions, SQS / Lambda / HTTP delivery, tagging
S3In-processVersioning, multipart upload, pre-signed URLs, Object Lock, event notifications
DynamoDBIn-processGSI / LSI, Query, Scan, TTL, transactions, batch operations
DynamoDB StreamsIn-processShard iterators, records, Lambda ESM trigger
LambdaReal Docker containersWarm pool, aliases, Function URLs, SQS / Kinesis / DDB Streams ESM
API Gateway RESTIn-processResources, methods, stages, Lambda proxy, MOCK integrations, AWS integrations
API Gateway v2 (HTTP)In-processRoutes, integrations, JWT authorizers, stages
IAMIn-processUsers, roles, groups, policies, instance profiles, access keys
STSIn-processAssumeRole, WebIdentity, SAML, GetFederationToken, GetSessionToken
CognitoIn-processUser pools, app clients, auth flows, JWKS / OpenID well-known endpoints
KMSIn-processEncrypt / decrypt, sign / verify, data keys, aliases
KinesisIn-processStreams, shards, enhanced fan-out, split / merge
Secrets ManagerIn-processVersioning, resource policies, tagging
Step FunctionsIn-processASL execution, task tokens, execution history
CloudFormationIn-processStacks, change sets, resource provisioning
EventBridgeIn-processCustom buses, rules, targets (SQS / SNS / Lambda)
EventBridge SchedulerIn-processSchedule groups, schedules, flexible time windows, retry policies, dead-letter queues
CloudWatch LogsIn-processLog groups, streams, ingestion, filtering
CloudWatch MetricsIn-processCustom metrics, statistics, alarms
ElastiCacheReal Docker containersRedis / Valkey, IAM auth, SigV4 validation
RDSReal Docker containersPostgreSQL & MySQL, IAM auth, JDBC-compatible
MSKReal Docker containersKafka compatible via Redpanda orchestration
AthenaIn-process + DuckDB sidecarReal SQL execution; Glue-backed views over S3 data; read_parquet / read_json_auto / read_csv_auto inferred from SerDe
GlueIn-processData Catalog; Schema Registry for Avro / JSON Schema / Protobuf; tables consumed by Athena as DuckDB views at query time
Data FirehoseIn-processStreaming data delivery; records flushed as NDJSON to S3
ECSReal Docker containersClusters, task definitions, tasks, services, capacity providers, task sets
EC2Real Docker containersRunInstances launches real Docker containers; SSH key injection; UserData execution; IMDS (IMDSv1+IMDSv2, port 9169) with IAM credential serving; VPCs, subnets, security groups, AMIs, key pairs, internet gateways, route tables, Elastic IPs, tags
ACMIn-processCertificate issuance, validation lifecycle
ECRIn-process + real OCI registryRepositories, image push / pull via stock docker, image-backed Lambda functions
SESIn-processSend email / raw email, identity verification, DKIM attributes, email templates with {{var}} substitution
SES v2 (HTTP)In-processREST JSON API, identities, DKIM, feedback attributes, account sending, email templates with {{var}} substitution
OpenSearchReal Docker containersDomain CRUD, tags, versions, instance types, upgrade stubs
AppConfigIn-processApplications, environments, profiles, hosted configuration versions, deployments
AppConfigDataIn-processConfiguration sessions, dynamic configuration retrieval
Bedrock RuntimeIn-process (stub)Dummy Converse and InvokeModel responses for local development; streaming returns 501
EKSReal Docker containers (mock mode available)Clusters, tagging; real mode starts k3s per cluster with a live Kubernetes API server
ELB v2In-processApplication and Network Load Balancers, target groups, listeners, path/host-based routing rules, Lambda targets (ALB→Lambda event format), tags
CodeBuildIn-process + real Docker containersProjects, report groups, source credentials; StartBuild runs real Docker containers, streams logs to CloudWatch, uploads artifacts to S3 via docker cp (works in Docker-in-Docker)
CodeDeployIn-process + Lambda traffic shiftingApplications, deployment groups, deployment configs; 17 CodeDeployDefault.* built-ins pre-seeded; CreateDeployment shifts Lambda alias RoutingConfig weights, invokes lifecycle hooks, auto-rolls back on failure
Auto ScalingIn-process + background reconcilerLaunch configurations, auto scaling groups with min/max/desired capacity; background loop (10 s) calls RunInstances / TerminateInstances to meet desired capacity; lifecycle hooks, scaling policies, ELB v2 target group auto-registration
AWS BackupIn-processVaults, backup plans with rules, resource selections, on-demand jobs with simulated lifecycle (CREATED → RUNNING → COMPLETED), recovery points, tagging
Route53In-processHosted zones with auto-created SOA + NS records, resource record sets (CREATE/UPSERT/DELETE with atomic validation), change tracking (always INSYNC), health checks, and per-resource tagging
Transfer FamilyIn-processServer lifecycle (CreateServer / DeleteServer / StartServer / StopServer / UpdateServer), user management, SSH public key import, and tagging
TextractIn-process (stub)API-compatible stubs for all operations; dummy block data with realistic shape and metadata; async job simulation with immediate SUCCEEDED status

Lambda, ElastiCache, RDS, MSK, ECS, EC2, EKS, OpenSearch, and CodeBuild spin up real Docker containers and support IAM authentication and SigV4 request signing — the same auth flow as production AWS. ECR runs a shared registry:2 container so the stock docker client can push and pull image bytes against repositories returned by the AWS-shaped control plane.

For per-service operation counts and endpoint protocols, see the Services Overview in the documentation site.

46 AWS services supported.

Persistence & Storage Modes

Floci features a flexible storage architecture designed to balance developer productivity, performance, and data durability. You can configure the storage mode globally via FLOCI_STORAGE_MODE or override it for specific services.

ModeBehaviorBest for...Durability
memory(Default) Entirely in-RAM. Data is lost when the container stops.Speed, ephemeral testing, CI pipelines.❌ None
persistentData is loaded at startup and flushed to disk on graceful shutdown.Simple local dev with state preservation.⚠️ Medium
hybridIn-memory performance with periodic async flushing (every 5s).The perfect balance of speed and safety.✅ Good
walWrite-Ahead Log. Every mutation is logged to disk before responding.Maximum durability for critical state.💎 Highest

[!TIP] The default memory mode is ideal for fast, ephemeral CI pipelines where state doesn't need to survive restarts. Switch to hybrid for local development when you want state preserved across container restarts without sacrificing performance.

For more details, visit the Storage Configuration documentation.

Multi-Account Isolation

Floci supports full per-account resource isolation with no extra configuration. If your AWS access key ID is exactly 12 digits, Floci uses it directly as the account ID — resources created by one account are completely invisible to another.

# Two accounts, full isolation — same queue name, separate namespaces AWS_ACCESS_KEY_ID=111111111111 aws sqs create-queue --queue-name orders AWS_ACCESS_KEY_ID=222222222222 aws sqs create-queue --queue-name orders

Any other key format (e.g. test, AKIA…) falls back to FLOCI_DEFAULT_ACCOUNT_ID (000000000000 by default) — the standard single-account setup.

Multi-Account Isolation docs

Quick Start

# docker-compose.yml services: floci: image: floci/floci:latest ports: - "4566:4566" volumes: # Local directory bind mount (default) - ./data:/app/data # OR named volume (optional): # - floci-data:/app/data #volumes: # floci-data:
docker compose up

Or run Floci directly with Docker:

docker run -d --name floci \ -p 4566:4566 \ -v /var/run/docker.sock:/var/run/docker.sock \ -e FLOCI_DEFAULT_REGION=us-east-1 \ -u root \ floci/floci:latest

All services are available at http://localhost:4566. Use any AWS region — credentials can be anything.

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 # Try it aws s3 mb s3://my-bucket aws sqs create-queue --queue-name my-queue aws dynamodb list-tables

SDK Integration

Point your existing AWS SDK at http://localhost:4566 — no other changes needed.

// Java (AWS SDK v2) var client = DynamoDbClient.builder() .endpointOverride(URI.create("http://localhost:4566")) .region(Region.US_EAST_1) .credentialsProvider(StaticCredentialsProvider.create( AwsBasicCredentials.create("test", "test"))) .build(); client.createTable(b -> b .tableName("demo-table") .billingMode(BillingMode.PAY_PER_REQUEST) .attributeDefinitions( AttributeDefinition.builder().attributeName("pk").attributeType(ScalarAttributeType.S).build()) .keySchema( KeySchemaElement.builder().attributeName("pk").keyType(KeyType.HASH).build())); client.putItem(b -> b .tableName("demo-table") .item(Map.of("pk", AttributeValue.fromS("item-1")))); System.out.println(client.listTables().tableNames());
# Python (boto3) import boto3 client = boto3.client("ssm", endpoint_url="http://localhost:4566", region_name="us-east-1", aws_access_key_id="test", aws_secret_access_key="test") client.put_parameter( Name="/demo/app/message", Value="hello from floci", Type="String", Overwrite=True, ) response = client.get_parameter(Name="/demo/app/message") print(response["Parameter"]["Value"])
// consumer.mjs // Node.js (AWS SDK v3) import {DeleteMessageCommand, ReceiveMessageCommand, SQSClient,} from "@aws-sdk/client-sqs"; const client = new SQSClient({ endpoint: "http://localhost:4566", region: "us-east-1", credentials: {accessKeyId: "test", secretAccessKey: "test"}, }); const QUEUE_URL = "http://localhost:4566/000000000000/demo-queue"; const response = await client.send( new ReceiveMessageCommand({ QueueUrl: QUEUE_URL, MaxNumberOfMessages: 1, WaitTimeSeconds: 5, }), ); if (response.Messages) { for (const msg of response.Messages) { console.log("Message received:", msg.Body); await client.send( new DeleteMessageCommand({ QueueUrl: QUEUE_URL, ReceiptHandle: msg.ReceiptHandle, }), ); } }
// producer.mjs // Node.js (AWS SDK v3) import {SendMessageCommand, SQSClient} from "@aws-sdk/client-sqs"; const client = new SQSClient({ endpoint: "http://localhost:4566", region: "us-east-1", credentials: {accessKeyId: "test", secretAccessKey: "test"}, }); const QUEUE_URL = "http://localhost:4566/000000000000/demo-queue"; await client.send( new SendMessageCommand({ QueueUrl: QUEUE_URL, MessageBody: "hello from producer", }), ); console.log("Message sent");
// Go (AWS SDK v2) package main import ( "context" "fmt" "log" "strings" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/credentials" "github.com/aws/aws-sdk-go-v2/service/s3" ) func main() { cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion("us-east-1"), config.WithCredentialsProvider( credentials.NewStaticCredentialsProvider("test", "test", ""), ), config.WithBaseEndpoint("http://localhost:4566"), ) if err != nil { log.Fatal(err) } client := s3.NewFromConfig(cfg, func(o *s3.Options) { o.UsePathStyle = true }) _, err = client.CreateBucket(context.TODO(), &s3.CreateBucketInput{ Bucket: aws.String("demo-bucket"), }) if err != nil { log.Fatal(err) } _, err = client.PutObject(context.TODO(), &s3.PutObjectInput{ Bucket: aws.String("demo-bucket"), Key: aws.String("demo.txt"), Body: strings.NewReader("hello from floci"), }) if err != nil { log.Fatal(err) } out, err := client.ListObjectsV2(context.TODO(), &s3.ListObjectsV2Input{ Bucket: aws.String("demo-bucket"), }) if err != nil { log.Fatal(err) } if len(out.Contents) > 0 { fmt.Println(*out.Contents[0].Key) } }
// Rust (AWS SDK) use aws_sdk_secretsmanager::config::{Credentials, Region}; use aws_sdk_secretsmanager::Client; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { let config = aws_config::defaults(aws_config::BehaviorVersion::latest()) .region(Region::new("us-east-1")) .credentials_provider(Credentials::new("test", "test", None, None, "floci")) .endpoint_url("http://localhost:4566") .load() .await; let client = Client::new(&config); client .create_secret() .name("demo/secret") .secret_string("hello from floci") .send() .await?; let secret = client .get_secret_value() .secret_id("demo/secret") .send() .await?; println!("{}", secret.secret_string().unwrap()); Ok(()) }
# Bash (AWS CLI) export AWS_ACCESS_KEY_ID=test export AWS_SECRET_ACCESS_KEY=test export AWS_DEFAULT_REGION=us-east-1 tmp_file="$(mktemp)" echo "hello from floci" > "$tmp_file" aws --endpoint-url http://localhost:4566 s3 mb s3://my-bucket aws --endpoint-url http://localhost:4566 s3 cp "$tmp_file" s3://my-bucket/demo.txt aws --endpoint-url http://localhost:4566 s3 ls s3://my-bucket # Cleanup aws --endpoint-url http://localhost:4566 s3 rm s3://my-bucket/demo.txt rm -f "$tmp_file"

Testcontainers

Floci has first-class Testcontainers modules so you can start a real Floci instance from your tests with zero manual setup — no running daemon, no shared state, no port conflicts.

LanguagePackageLatestRegistrySource
Javaio.floci:testcontainers-floci1.4.0Maven CentralGitHub
Node.js@floci/testcontainers0.1.0npmGitHub
Pythontestcontainers-floci0.1.1PyPIGitHub
Go🚧 In progressGitHub

Java

Add the dependency (Testcontainers 1.x / Spring Boot 3.x):

<dependency> <groupId>io.floci</groupId> <artifactId>testcontainers-floci</artifactId> <version>1.4.0</version> <scope>test</scope> </dependency>

For Testcontainers 2.x / Spring Boot 4.x use version 2.5.0.

Basic usage with JUnit 5:

@Testcontainers class S3IntegrationTest { @Container static FlociContainer floci = new FlociContainer(); @Test void shouldCreateBucket() { S3Client s3 = S3Client.builder() .endpointOverride(URI.create(floci.getEndpoint())) .region(Region.of(floci.getRegion())) .credentialsProvider(StaticCredentialsProvider.create( AwsBasicCredentials.create(floci.getAccessKey(), floci.getSecretKey()))) .forcePathStyle(true) .build(); s3.createBucket(b -> b.bucket("my-bucket")); assertThat(s3.listBuckets().buckets()) .anyMatch(b -> b.name().equals("my-bucket")); } }

Spring Boot — add spring-boot-testcontainers-floci and use @ServiceConnection for zero-config auto-wiring:

@SpringBootTest @Testcontainers class AppIntegrationTest { @Container @ServiceConnection static FlociContainer floci = new FlociContainer(); @Autowired S3Client s3; @Test void shouldCreateBucket() { s3.createBucket(b -> b.bucket("my-bucket")); assertThat(s3.listBuckets().buckets()) .anyMatch(b -> b.name().equals("my-bucket")); } }

Node.js / TypeScript

npm install --save-dev @floci/testcontainers
import { FlociContainer } from "@floci/testcontainers"; import { S3Client, CreateBucketCommand, ListBucketsCommand } from "@aws-sdk/client-s3"; describe("S3", () => { let floci: FlociContainer; beforeAll(async () => { floci = await new FlociContainer().start(); }); afterAll(async () => { await floci.stop(); }); it("should create and list a bucket", async () => { const s3 = new S3Client({ endpoint: floci.getEndpoint(), region: floci.getRegion(), credentials: { accessKeyId: floci.getAccessKey(), secretAccessKey: floci.getSecretKey(), }, forcePathStyle: true, }); await s3.send(new CreateBucketCommand({ Bucket: "my-bucket" })); const { Buckets } = await s3.send(new ListBucketsCommand({})); expect(Buckets?.some(b => b.Name === "my-bucket")).toBe(true); }); });

Python

pip install testcontainers-floci
import boto3 from testcontainers_floci import FlociContainer def test_s3_create_bucket(): with FlociContainer() as floci: s3 = boto3.client( "s3", endpoint_url=floci.get_endpoint(), region_name=floci.get_region(), aws_access_key_id=floci.get_access_key(), aws_secret_access_key=floci.get_secret_key(), ) s3.create_bucket(Bucket="my-bucket") buckets = s3.list_buckets()["Buckets"] assert any(b["Name"] == "my-bucket" for b in buckets)

Pytest fixture style:

import pytest import boto3 from testcontainers_floci import FlociContainer @pytest.fixture(scope="session") def floci(): with FlociContainer() as container: yield container def test_s3_create_bucket(floci): s3 = boto3.client( "s3", endpoint_url=floci.get_endpoint(), region_name=floci.get_region(), aws_access_key_id=floci.get_access_key(), aws_secret_access_key=floci.get_secret_key(), ) s3.create_bucket(Bucket="my-bucket") buckets = s3.list_buckets()["Buckets"] assert any(b["Name"] == "my-bucket" for b in buckets)

Go

Go support is in progress. Track it at testcontainers-floci-go.

Compatibility Testing

For full compatibility validation against real SDK and client workflows, see the compatibility-tests directory.

This directory provides a dedicated compatibility test suite for Floci across multiple SDKs and tooling scenarios, and is the recommended starting point when verifying integration behavior end to end.

Available compatibility test modules:

ModuleLanguage / ToolSDK / Client / VersionTests
sdk-test-javaJava 17AWS SDK for Java v2889
sdk-test-nodeNode.jsAWS SDK for JavaScript v3360
sdk-test-pythonPython 3boto3264
sdk-test-goGoAWS SDK for Go v2136
sdk-test-awscliBashAWS CLI v2145
sdk-test-rustRustAWS SDK for Rust86
compat-terraformTerraformv1.10+14
compat-opentofuOpenTofuv1.9+14
compat-cdkAWS CDKv2+17

1,850+ automated compatibility tests across 6 SDKs and 3 IaC tools.

Image Tags

Every tag combines two choices: variant (what's inside) and channel (how stable).

StandardCompat (+ AWS CLI + boto3)
Release (latest)latestlatest-compat
Release (pinned)x.y.zx.y.z-compat
Nightly (floating)nightlynightly-compat
Nightly (dated)nightly-mmddyyyynightly-mmddyyyy-compat
  • Standard — GraalVM native binary. ~24 ms startup, ~40 MB image, ~13 MiB idle memory.
  • Compat — Extends the standard image with Python 3, AWS CLI, and boto3. Same startup and memory, larger image.
  • Release — Published on every stable version tag.
  • Nightly — Built every night at 22:00 CT from main. Dated tags (e.g. nightly-05022026) are fixed; nightly always points to the latest.
# Recommended image: floci/floci:latest # With AWS CLI + boto3 image: floci/floci:latest-compat # Pinned image: floci/floci:1.5.11 # Track main image: floci/floci:nightly

Configuration

All settings are overridable via environment variables (FLOCI_ prefix).

VariableDefaultDescription
FLOCI_PORT4566Port exposed by the Floci API
FLOCI_DEFAULT_REGIONus-east-1Default AWS region
FLOCI_DEFAULT_ACCOUNT_ID000000000000Default AWS account ID
FLOCI_BASE_URLhttp://localhost:4566Base URL used when Floci returns service URLs (e.g. SQS QueueUrl)
FLOCI_HOSTNAME(unset)Hostname to use in returned URLs when Floci runs inside Docker Compose
FLOCI_STORAGE_MODEmemoryControls how data is stored across runs: memory · persistent · hybrid · wal
FLOCI_STORAGE_PERSISTENT_PATH./dataDirectory used for persisted state
FLOCI_ECR_BASE_URIpublic.ecr.awsAWS ECR base URI used when pulling container images (e.g. Lambda)

Multi-container Docker Compose: When your application runs in a separate container from Floci, set FLOCI_HOSTNAME to the Floci service name so that returned URLs (e.g. SQS QueueUrl) resolve correctly:

services: floci: image: floci/floci:latest ports: - "4566:4566" environment: - FLOCI_HOSTNAME=floci # URLs will use http://floci:4566/... my-app: environment: - AWS_ENDPOINT_URL=http://floci:4566 depends_on: - floci

Without this, SQS returns http://localhost:4566/... in QueueUrl responses, which resolves to the wrong container.

Star history

Star History Chart

Contributors

License

MIT — use it however you want.

关于 About

Light, fluffy, and always free - The AWS Local Emulator alternative
awsaws-emulationdevopsdockerec2ecslocalstacks3sqstestcontainers

语言 Languages

Java91.0%
TypeScript2.4%
Python2.4%
Shell1.6%
Rust1.3%
Go1.0%
HCL0.2%
Dockerfile0.1%
Just0.0%
JavaScript0.0%

提交活跃度 Commit Activity

代码提交热力图
过去 52 周的开发活跃度
534
Total Commits
峰值: 112次/周
Less
More

核心贡献者 Contributors