[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-74487":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":18,"stars30d":19,"stars90d":16,"forks30d":16,"starsTrendScore":20,"compositeScore":21,"rankGlobal":10,"rankLanguage":10,"license":22,"archived":23,"fork":23,"defaultBranch":24,"hasWiki":23,"hasPages":25,"topics":26,"createdAt":10,"pushedAt":10,"updatedAt":37,"readmeContent":38,"aiSummary":39,"trendingCount":16,"starSnapshotCount":16,"syncStatus":40,"lastSyncTime":41,"discoverSource":42},74487,"floci","floci-io\u002Ffloci","floci-io","Light, fluffy, and always free - The AWS Local Emulator alternative","https:\u002F\u002Ffloci.io",null,"Java",13980,1344,52,54,0,58,364,1774,296,44.39,"MIT License",false,"main",true,[27,28,29,30,31,32,33,34,35,36],"aws","aws-emulation","devops","docker","ec2","ecs","localstack","s3","sqs","testcontainers","2026-06-12 02:03:26","\u003Cp align=\"center\">\n  \u003Cimg src=\"floci_banner.svg\" alt=\"Floci\"\u002F>\n\u003C\u002Fp>\n\n\u003Cp align=\"center\">\n  \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Ffloci-io\u002Ffloci\u002Freleases\u002Flatest\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Fv\u002Frelease\u002Ffloci-io\u002Ffloci?label=latest%20release&color=blue\" alt=\"Latest Release\">\u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Ffloci-io\u002Ffloci\u002Factions\u002Fworkflows\u002Frelease.yml\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Factions\u002Fworkflow\u002Fstatus\u002Ffloci-io\u002Ffloci\u002Frelease.yml?label=build\" alt=\"Build Status\">\u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fhub.docker.com\u002Fr\u002Ffloci\u002Ffloci\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fdocker\u002Fpulls\u002Ffloci\u002Ffloci?label=docker%20pulls\" alt=\"Docker Pulls\">\u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fhub.docker.com\u002Fr\u002Ffloci\u002Ffloci\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fdocker\u002Fimage-size\u002Ffloci\u002Ffloci\u002Flatest?label=image%20size\" alt=\"Docker Image Size\">\u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fopensource.org\u002Flicenses\u002FMIT\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flicense-MIT-green\" alt=\"License: MIT\">\u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Ffloci-io\u002Ffloci\u002Fstargazers\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Fstars\u002Ffloci-io\u002Ffloci?style=flat\" alt=\"GitHub Stars\">\u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Ffloci-io\u002Ffloci\u002Fgraphs\u002Fcontributors\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Fcontributors\u002Ffloci-io\u002Ffloci\" alt=\"GitHub Contributors\">\u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fjoin.slack.com\u002Ft\u002Ffloci\u002Fshared_invite\u002Fzt-3tjn02s3q-A00kEjJ1cZxsg_imTfy6Cw\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FSlack-Join%20the%20community-4A154B?logo=slack&logoColor=white\" alt=\"Join Floci on Slack\">\u003C\u002Fa>\n\u003C\u002Fp>\n\n\u003Cp align=\"center\">\n  \u003Cstrong>A free, open-source local AWS emulator.\u003C\u002Fstrong>\u003Cbr\u002F>\n  No account. No feature gates. Just&nbsp;\u003Ccode>docker compose up\u003C\u002Fcode>.\n\u003C\u002Fp>\n\n\u003Cp align=\"center\">\n  \u003Cem>Named after \u003Ca href=\"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FCirrocumulus_floccus\">floccus\u003C\u002Fa> — the cloud formation that looks exactly like popcorn.\u003C\u002Fem>\n\u003C\u002Fp>\n\n\u003Cp align=\"center\">\n  Join us on \u003Ca href=\"https:\u002F\u002Fjoin.slack.com\u002Ft\u002Ffloci\u002Fshared_invite\u002Fzt-3tjn02s3q-A00kEjJ1cZxsg_imTfy6Cw\">Slack\u003C\u002Fa> or \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Forgs\u002Ffloci-io\u002Fdiscussions\">GitHub Discussions\u003C\u002Fa> — feature ideas, compatibility questions, design tradeoffs, wild proposals, and half-baked thoughts are all welcome.\n\u003C\u002Fp>\n\n---\n\n> [!IMPORTANT]\n> **Image moved to `floci\u002Ffloci`.** Update your `docker-compose.yml` and `docker run` commands:\n> ```\n> # Before\n> image: hectorvent\u002Ffloci:latest\n> # After\n> image: floci\u002Ffloci:latest\n> ```\n> The old `hectorvent\u002Ffloci` repository will no longer receive updates.\n---\n\n## Table of Contents\n\n- [Why Floci?](#why-floci)\n- [Quick Start](#quick-start)\n- [Architecture Overview](#architecture-overview)\n- [Real Docker Integration](#real-docker-integration)\n- [Supported Services](#supported-services)\n- [Persistence & Storage Modes](#persistence--storage-modes)\n- [Multi-Account Isolation](#multi-account-isolation)\n- [SDK Integration](#sdk-integration)\n- [Testcontainers](#testcontainers)\n- [Compatibility Testing](#compatibility-testing)\n- [Image Tags](#image-tags)\n- [Configuration](#configuration)\n- [Migrating from LocalStack](#migrating-from-localstack)\n- [Contributors](#contributors)\n- [License](#license)\n\n---\n\n## Why Floci?\n\n> LocalStack's community edition [sunset in March 2026](https:\u002F\u002Fblog.localstack.cloud\u002Fthe-road-ahead-for-localstack\u002F), requiring auth tokens and freezing security updates. Floci is the no-strings-attached alternative.\n\n| | Floci | LocalStack Community |\n|---|:---:|:---:|\n| Auth token required | ❌ No | ✅ Yes (since March 2026) |\n| Security updates | ✅ Yes | ❌ Frozen |\n| Startup time | **~24 ms** | ~3.3 s |\n| Idle memory | **~13 MiB** | ~143 MiB |\n| Docker image size | **~90 MB** | ~1.0 GB |\n| License | **MIT** | Restricted |\n| API Gateway v2 \u002F HTTP API | ✅ | ❌ |\n| Cognito | ✅ | ❌ |\n| ElastiCache (Redis + IAM auth) | ✅ | ❌ |\n| RDS (PostgreSQL + MySQL + IAM auth) | ✅ | ❌ |\n| MSK (Kafka + Redpanda) | ✅ | ❌ |\n| Athena (real SQL via DuckDB sidecar + Glue views) | ✅ | ❌ |\n| Glue Data Catalog + Schema Registry | ✅ | ❌ |\n| Data Firehose (NDJSON delivery) | ✅ | ❌ |\n| S3 Object Lock (COMPLIANCE \u002F GOVERNANCE) | ✅ | ⚠️ Partial |\n| DynamoDB Streams | ✅ | ⚠️ Partial |\n| IAM (users, roles, policies, groups) | ✅ | ⚠️ Partial |\n| STS (all 7 operations) | ✅ | ⚠️ Partial |\n| Kinesis (streams, shards, fan-out) | ✅ | ⚠️ Partial |\n| KMS (sign, verify, re-encrypt) | ✅ | ⚠️ Partial |\n| ECS (clusters, services, tasks) | ✅ | ❌ |\n| EKS (clusters, mock + real k3s) | ✅ | ❌ |\n| EC2 (real Docker instances, IMDS, SSH, UserData) | ✅ | ❌ |\n| CodeBuild (real Docker build execution, S3 artifacts, CloudWatch logs) | ✅ | ❌ |\n| CodeDeploy (Lambda traffic shifting, lifecycle hooks, auto-rollback) | ✅ | ❌ |\n| Auto Scaling (groups, launch configs, reconciler, ELB v2 integration) | ✅ | ❌ |\n| SSM Run Command (SendCommand + real agent polling via ec2messages) | ✅ | ❌ |\n| Transfer Family (SFTP server management, users, SSH keys) | ✅ | ❌ |\n| Native binary | ✅ ~40 MB | ❌ |\n\n**47 AWS services. Broad coverage. Free forever.**\n\n---\n\n## Quick Start\n\n```yaml\n# docker-compose.yml\nservices:\n  floci:\n    image: floci\u002Ffloci:latest\n    ports:\n      - \"4566:4566\"\n    volumes:\n      - .\u002Fdata:\u002Fapp\u002Fdata\n```\n\n```bash\ndocker compose up\n```\n\nOr run directly with Docker:\n\n```bash\ndocker run -d --name floci \\\n  -p 4566:4566 \\\n  -v \u002Fvar\u002Frun\u002Fdocker.sock:\u002Fvar\u002Frun\u002Fdocker.sock \\\n  -e FLOCI_DEFAULT_REGION=us-east-1 \\\n  -u root \\\n  floci\u002Ffloci:latest\n```\n\nAll services are available at `http:\u002F\u002Flocalhost:4566`. Any region works. Credentials can be anything.\n\n```bash\nexport AWS_ENDPOINT_URL=http:\u002F\u002Flocalhost:4566\nexport AWS_DEFAULT_REGION=us-east-1\nexport AWS_ACCESS_KEY_ID=test\nexport AWS_SECRET_ACCESS_KEY=test\n\naws s3 mb s3:\u002F\u002Fmy-bucket\naws sqs create-queue --queue-name my-queue\naws dynamodb list-tables\n```\n\n---\n\n## Architecture Overview\n\n```mermaid\nflowchart LR\n    Client[\"☁️ AWS SDK \u002F CLI\"]\n\n    subgraph Floci [\"Floci — port 4566\"]\n        Router[\"HTTP Router\\n(JAX-RS \u002F Vert.x)\"]\n\n        subgraph Stateless [\"Stateless Services\"]\n            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\"]\n        end\n\n        subgraph Stateful [\"Stateful Services\"]\n            B[\"S3 · DynamoDB\\nDynamoDB Streams\"]\n        end\n\n        subgraph Containers [\"Container Services  🐳\"]\n            C[\"Lambda\\nElastiCache\\nRDS\\nECS\\nEC2\\nMSK\\nEKS\\nOpenSearch\\nCodeBuild\"]\n            D[\"Athena ➜ floci-duck\\n(DuckDB sidecar)\"]\n        end\n\n        Router --> Stateless\n        Router --> Stateful\n        Router --> Containers\n        Stateless & Stateful --> Store[(\"StorageBackend\\nmemory · hybrid\\npersistent · wal\")]\n    end\n\n    Docker[\"🐳 Docker Engine\"]\n    Client -->|\"HTTP :4566\\nAWS wire protocol\"| Router\n    Containers -->|\"Docker API\\n+ IAM \u002F SigV4 auth\"| Docker\n```\n\n---\n\n## Real Docker Integration\n\nUnlike 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.\n\n| Service | Default Image | What's real |\n|---|---|---|\n| **Lambda** | `public.ecr.aws\u002Flambda\u002F\u003Cruntime>` | AWS runtime environment, execution model, warm container pool |\n| **ElastiCache** | `valkey\u002Fvalkey:8` | Full Redis\u002FValkey protocol, ACL-based IAM auth, SigV4 validation |\n| **RDS (PostgreSQL)** | `postgres:16-alpine` | Real PostgreSQL engine, IAM auth via token, JDBC-compatible |\n| **RDS (MySQL \u002F Aurora)** | `mysql:8.0` | Real MySQL engine, IAM auth, JDBC-compatible |\n| **RDS (MariaDB)** | `mariadb:11` | Real MariaDB engine, IAM auth, JDBC-compatible |\n| **MSK** | `redpandadata\u002Fredpanda:latest` | Real Kafka-compatible broker via Redpanda |\n| **EC2** | AMI-mapped (e.g. `public.ecr.aws\u002Famazonlinux\u002Famazonlinux:2023`) | Real Linux containers; SSH key injection; UserData execution; IMDS with IMDSv1+IMDSv2 and IAM credential serving |\n| **ECS** | User-specified in task definition | Actual container lifecycle — start, stop, health checks |\n| **EKS** | `rancher\u002Fk3s:latest` | Live Kubernetes API server (k3s), full kubeconfig |\n| **CodeBuild** | User-specified environment image | Real buildspec execution — install\u002Fpre_build\u002Fbuild\u002Fpost_build phases in container; S3 artifact upload; CloudWatch log streaming |\n| **OpenSearch** | `opensearchproject\u002Fopensearch:2` | Full OpenSearch engine with REST API |\n| **ECR** | `registry:2` | Real OCI-compatible registry — `docker push` \u002F `docker pull` work natively |\n\n### Lambda runtimes\n\nFloci resolves each Lambda runtime to the corresponding [AWS public ECR image](https:\u002F\u002Fgallery.ecr.aws\u002Flambda):\n\n| Runtime | Image |\n|---|---|\n| `java25` · `java21` · `java17` · `java11` · `java8.al2` · `java8` | `public.ecr.aws\u002Flambda\u002Fjava:\u003Cversion>` |\n| `python3.14` · `python3.13` · `python3.12` · `python3.11` · `python3.10` · `python3.9` | `public.ecr.aws\u002Flambda\u002Fpython:\u003Cversion>` |\n| `nodejs24.x` · `nodejs22.x` · `nodejs20.x` · `nodejs18.x` · `nodejs16.x` | `public.ecr.aws\u002Flambda\u002Fnodejs:\u003Cversion>` |\n| `ruby3.4` · `ruby3.3` · `ruby3.2` | `public.ecr.aws\u002Flambda\u002Fruby:\u003Cversion>` |\n| `dotnet10` · `dotnet9` · `dotnet8` · `dotnet6` | `public.ecr.aws\u002Flambda\u002Fdotnet:\u003Cversion>` |\n| `go1.x` | `public.ecr.aws\u002Flambda\u002Fgo:1` |\n| `provided.al2023` · `provided.al2` · `provided` | `public.ecr.aws\u002Flambda\u002Fprovided:\u003Cvariant>` |\n\nContainer image functions (package type `Image`) pass the `ImageUri` through directly, with ECR repository URIs rewritten to the local Floci ECR endpoint automatically.\n\n### Requirements\n\nDocker-backed services require the Docker socket to be accessible:\n\n```bash\ndocker run -d --name floci \\\n  -p 4566:4566 \\\n  -v \u002Fvar\u002Frun\u002Fdocker.sock:\u002Fvar\u002Frun\u002Fdocker.sock \\\n  -u root \\\n  floci\u002Ffloci:latest\n```\n\nIn Docker Compose, add the socket volume alongside any other mounts.\n\n### Overriding default images\n\nAll default images are configurable via environment variables — useful for pinning versions or using a local mirror:\n\n| Variable | Default |\n|---|---|\n| `FLOCI_SERVICES_ELASTICACHE_DEFAULT_IMAGE` | `valkey\u002Fvalkey:8` |\n| `FLOCI_SERVICES_RDS_DEFAULT_POSTGRES_IMAGE` | `postgres:16-alpine` |\n| `FLOCI_SERVICES_RDS_DEFAULT_MYSQL_IMAGE` | `mysql:8.0` |\n| `FLOCI_SERVICES_RDS_DEFAULT_MARIADB_IMAGE` | `mariadb:11` |\n| `FLOCI_SERVICES_MSK_DEFAULT_IMAGE` | `redpandadata\u002Fredpanda:latest` |\n| `FLOCI_SERVICES_OPENSEARCH_DEFAULT_IMAGE` | `opensearchproject\u002Fopensearch:2` |\n| `FLOCI_SERVICES_EKS_DEFAULT_IMAGE` | `rancher\u002Fk3s:latest` |\n| `FLOCI_SERVICES_ECR_REGISTRY_IMAGE` | `registry:2` |\n| `FLOCI_ECR_BASE_URI` | `public.ecr.aws` (Lambda runtime base) |\n\n---\n\n## Supported Services\n\n> **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.\n>\n> For per-service operation counts and endpoint protocols, see the [Services Overview](https:\u002F\u002Ffloci.io\u002Ffloci\u002Fservices\u002F) in the documentation site.\n\n| Service | How it works | Notable features |\n|---|---|---|\n| **SSM Parameter Store** | In-process | Version history, labels, SecureString, tagging |\n| **SSM Run Command** | In-process | `SendCommand`, `GetCommandInvocation`, `ListCommands`, `CancelCommand`; `DescribeInstanceInformation`; `ec2messages` polling so the real `amazon-ssm-agent` can register, receive commands, and report output |\n| **SQS** | In-process | Standard & FIFO, DLQ, visibility timeout, batch, tagging |\n| **SNS** | In-process | Topics, subscriptions, SQS \u002F Lambda \u002F HTTP delivery, tagging |\n| **S3** | In-process | Versioning, multipart upload, pre-signed URLs, Object Lock, event notifications |\n| **DynamoDB** | In-process | GSI \u002F LSI, Query, Scan, TTL, transactions, batch operations |\n| **DynamoDB Streams** | In-process | Shard iterators, records, Lambda ESM trigger |\n| **Lambda** | **Real Docker** | Warm pool, aliases, Function URLs, SQS \u002F Kinesis \u002F DDB Streams ESM |\n| **API Gateway REST** | In-process | Resources, methods, stages, Lambda proxy, MOCK integrations, AWS integrations |\n| **API Gateway v2 (HTTP)** | In-process | Routes, integrations, JWT authorizers, stages |\n| **IAM** | In-process | Users, roles, groups, policies, instance profiles, access keys |\n| **STS** | In-process | AssumeRole, WebIdentity, SAML, GetFederationToken, GetSessionToken |\n| **Cognito** | In-process | User pools, app clients, auth flows, JWKS \u002F OpenID well-known endpoints |\n| **KMS** | In-process | Encrypt \u002F decrypt, sign \u002F verify, data keys, aliases |\n| **Kinesis** | In-process | Streams, shards, enhanced fan-out, split \u002F merge |\n| **Secrets Manager** | In-process | Versioning, resource policies, tagging |\n| **Step Functions** | In-process | ASL execution, task tokens, execution history |\n| **CloudFormation** | In-process | Stacks, change sets, resource provisioning |\n| **EventBridge** | In-process | Custom buses, rules, targets (SQS \u002F SNS \u002F Lambda) |\n| **EventBridge Scheduler** | In-process | Schedule groups, schedules, flexible time windows, retry policies, dead-letter queues |\n| **CloudWatch Logs** | In-process | Log groups, streams, ingestion, filtering |\n| **CloudWatch Metrics** | In-process | Custom metrics, statistics, alarms |\n| **ElastiCache** | **Real Docker** | Redis \u002F Valkey, IAM auth, SigV4 validation |\n| **RDS** | **Real Docker** | PostgreSQL & MySQL, IAM auth, JDBC-compatible |\n| **MSK** | **Real Docker** | Kafka compatible via Redpanda orchestration |\n| **Athena** | In-process + **DuckDB sidecar** | Real SQL execution; Glue-backed views over S3 data; `read_parquet` \u002F `read_json_auto` \u002F `read_csv_auto` inferred from SerDe |\n| **Glue** | In-process | Data Catalog; Schema Registry for Avro \u002F JSON Schema \u002F Protobuf; tables consumed by Athena as DuckDB views at query time |\n| **Data Firehose** | In-process | Streaming data delivery; records flushed as NDJSON to S3 |\n| **ECS** | **Real Docker** | Clusters, task definitions, tasks, services, capacity providers, task sets |\n| **EC2** | **Real Docker** | `RunInstances` 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 |\n| **ACM** | In-process | Certificate issuance, validation lifecycle |\n| **ECR** | In-process + **real OCI registry** | Repositories, image push \u002F pull via stock `docker`, image-backed Lambda functions |\n| **SES** | In-process | Send email \u002F raw email, identity verification, DKIM attributes, email templates with `{{var}}` substitution |\n| **SES v2 (HTTP)** | In-process | REST JSON API, identities, DKIM, feedback attributes, account sending, email templates with `{{var}}` substitution |\n| **OpenSearch** | **Real Docker** | Domain CRUD, tags, versions, instance types, upgrade stubs |\n| **AppConfig** | In-process | Applications, environments, profiles, hosted configuration versions, deployments |\n| **AppConfigData** | In-process | Configuration sessions, dynamic configuration retrieval |\n| **Bedrock Runtime** | In-process (stub) | Dummy Converse and InvokeModel responses for local development; streaming returns 501 |\n| **EKS** | **Real Docker** (mock mode available) | Clusters, tagging; real mode starts k3s per cluster with a live Kubernetes API server |\n| **ELB v2** | In-process | Application and Network Load Balancers, target groups, listeners, path\u002Fhost-based routing rules, Lambda targets (ALB→Lambda event format), tags |\n| **CodeBuild** | In-process + **real Docker** | Projects, report groups, source credentials; `StartBuild` runs real Docker containers, streams logs to CloudWatch, uploads artifacts to S3 via `docker cp` |\n| **CodeDeploy** | In-process + **Lambda traffic shifting** | Applications, deployment groups, deployment configs; 17 `CodeDeployDefault.*` built-ins pre-seeded; `CreateDeployment` shifts Lambda alias `RoutingConfig` weights, invokes lifecycle hooks, auto-rolls back on failure |\n| **Auto Scaling** | In-process + **background reconciler** | Launch configurations, auto scaling groups with min\u002Fmax\u002Fdesired capacity; background loop (10 s) calls `RunInstances` \u002F `TerminateInstances` to meet desired capacity; lifecycle hooks, scaling policies, ELB v2 target group auto-registration |\n| **AWS Backup** | In-process | Vaults, backup plans with rules, resource selections, on-demand jobs with simulated lifecycle (CREATED → RUNNING → COMPLETED), recovery points, tagging |\n| **Route53** | In-process | Hosted zones with auto-created SOA + NS records, resource record sets (CREATE\u002FUPSERT\u002FDELETE with atomic validation), change tracking (always INSYNC), health checks, and per-resource tagging |\n| **Transfer Family** | In-process | Server lifecycle (`CreateServer` \u002F `DeleteServer` \u002F `StartServer` \u002F `StopServer` \u002F `UpdateServer`), user management, SSH public key import, and tagging |\n| **Textract** | In-process (stub) | API-compatible stubs for all operations; dummy block data with realistic shape and metadata; async job simulation with immediate SUCCEEDED status |\n| **Pricing (Price List Service)** | In-process + bundled static snapshot | `DescribeServices`, `GetAttributeValues`, `GetProducts`, `ListPriceLists`, `GetPriceListFileUrl`; pagination; filesystem override via `FLOCI_SERVICES_PRICING_SNAPSHOT_PATH` |\n| **Cost Explorer** | In-process; cost synthesized from Floci resource state × Pricing snapshot | `GetCostAndUsage` (full `Filter`\u002F`GroupBy`\u002F`Metrics`\u002F`RECORD_TYPE`), `GetCostAndUsageWithResources`, `GetDimensionValues`, `GetTags`, RI\u002FSP coverage+utilization stubs; CDI-discovered `ResourceUsageEnumerator` SPI for new services to emit cost lines without touching CE |\n| **Cost and Usage Reports (CUR)** | In-process management plane + `floci-duck` sidecar for Parquet emission | `PutReportDefinition`, `ModifyReportDefinition`, `DescribeReportDefinitions`, `DeleteReportDefinition`; FOCUS 1.2 \u002F CUR 2.0 columns; account-scoped storage; `synchronous` \u002F `daily` \u002F `off` emit modes |\n| **BCM Data Exports** | In-process management plane sharing the CUR Parquet engine | `CreateExport`, `GetExport`, `ListExports`, `UpdateExport`, `DeleteExport`, `ListExecutions`, `GetExecution`; AWS-compatible execution lifecycle (`INITIATION_IN_PROCESS` → `DELIVERY_SUCCESS` \u002F `DELIVERY_FAILURE`) |\n\n---\n\n## Persistence & Storage Modes\n\nFloci features a flexible storage architecture designed to balance developer productivity, performance, and data durability. Configure globally via `FLOCI_STORAGE_MODE` or override it per service.\n\n| Mode | Behavior | Best for | Durability |\n|:---:|---|---|:---:|\n| **`memory`** | **(Default)** Entirely in-RAM. Data is lost when the container stops. | Speed, ephemeral testing, CI pipelines | ❌ None |\n| **`persistent`** | Loaded at startup, flushed to disk on graceful shutdown. | Simple local dev with state preservation | ⚠️ Medium |\n| **`hybrid`** | In-memory performance with periodic async flushing every 5 seconds. | The best balance of speed and safety | ✅ Good |\n| **`wal`** | Write-Ahead Log. Every mutation is logged to disk before responding. | Maximum durability for critical state | 💎 Highest |\n\n> [!TIP]\n> The default **`memory`** mode is ideal for fast, ephemeral CI pipelines. Switch to **`hybrid`** for local development when you want state preserved across container restarts without sacrificing performance.\n\nFor more details, see the [Storage Configuration documentation](https:\u002F\u002Ffloci.io\u002Ffloci\u002Fconfiguration\u002Fstorage\u002F).\n\n---\n\n## Multi-Account Isolation\n\nFloci 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.\n\n```bash\n# Two accounts, full isolation — same queue name, separate namespaces\nAWS_ACCESS_KEY_ID=111111111111 aws sqs create-queue --queue-name orders\nAWS_ACCESS_KEY_ID=222222222222 aws sqs create-queue --queue-name orders\n```\n\nAny other key format (e.g. `test`, `AKIA…`) falls back to `FLOCI_DEFAULT_ACCOUNT_ID` (`000000000000` by default) — the standard single-account setup.\n\n→ [Multi-Account Isolation docs](https:\u002F\u002Ffloci.io\u002Ffloci\u002Fconfiguration\u002Fmulti-account\u002F)\n\n---\n\n## SDK Integration\n\nPoint your existing AWS SDK at `http:\u002F\u002Flocalhost:4566` — no other changes needed.\n\n\u003Cdetails>\n\u003Csummary>\u003Cstrong>Java (AWS SDK v2)\u003C\u002Fstrong>\u003C\u002Fsummary>\n\n```java\nvar client = DynamoDbClient.builder()\n    .endpointOverride(URI.create(\"http:\u002F\u002Flocalhost:4566\"))\n    .region(Region.US_EAST_1)\n    .credentialsProvider(StaticCredentialsProvider.create(\n        AwsBasicCredentials.create(\"test\", \"test\")))\n    .build();\n\nclient.createTable(b -> b\n    .tableName(\"demo-table\")\n    .billingMode(BillingMode.PAY_PER_REQUEST)\n    .attributeDefinitions(\n        AttributeDefinition.builder().attributeName(\"pk\").attributeType(ScalarAttributeType.S).build())\n    .keySchema(\n        KeySchemaElement.builder().attributeName(\"pk\").keyType(KeyType.HASH).build()));\n\nclient.putItem(b -> b\n    .tableName(\"demo-table\")\n    .item(Map.of(\"pk\", AttributeValue.fromS(\"item-1\"))));\n\nSystem.out.println(client.listTables().tableNames());\n```\n\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>\u003Cstrong>Python (boto3)\u003C\u002Fstrong>\u003C\u002Fsummary>\n\n```python\nimport boto3\nclient = boto3.client(\"ssm\",\n    endpoint_url=\"http:\u002F\u002Flocalhost:4566\",\n    region_name=\"us-east-1\",\n    aws_access_key_id=\"test\",\n    aws_secret_access_key=\"test\")\n\nclient.put_parameter(\n    Name=\"\u002Fdemo\u002Fapp\u002Fmessage\",\n    Value=\"hello from floci\",\n    Type=\"String\",\n    Overwrite=True,\n)\n\nresponse = client.get_parameter(Name=\"\u002Fdemo\u002Fapp\u002Fmessage\")\nprint(response[\"Parameter\"][\"Value\"])\n```\n\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>\u003Cstrong>Node.js (AWS SDK v3)\u003C\u002Fstrong>\u003C\u002Fsummary>\n\n```javascript\n\u002F\u002F consumer.mjs\nimport { DeleteMessageCommand, ReceiveMessageCommand, SQSClient } from \"@aws-sdk\u002Fclient-sqs\";\n\nconst client = new SQSClient({\n    endpoint: \"http:\u002F\u002Flocalhost:4566\",\n    region: \"us-east-1\",\n    credentials: { accessKeyId: \"test\", secretAccessKey: \"test\" },\n});\n\nconst QUEUE_URL = \"http:\u002F\u002Flocalhost:4566\u002F000000000000\u002Fdemo-queue\";\n\nconst response = await client.send(\n    new ReceiveMessageCommand({\n        QueueUrl: QUEUE_URL,\n        MaxNumberOfMessages: 1,\n        WaitTimeSeconds: 5,\n    }),\n);\n\nif (response.Messages) {\n    for (const msg of response.Messages) {\n        console.log(\"Message received:\", msg.Body);\n        await client.send(\n            new DeleteMessageCommand({\n                QueueUrl: QUEUE_URL,\n                ReceiptHandle: msg.ReceiptHandle,\n            }),\n        );\n    }\n}\n```\n\n```javascript\n\u002F\u002F producer.mjs\nimport { SendMessageCommand, SQSClient } from \"@aws-sdk\u002Fclient-sqs\";\n\nconst client = new SQSClient({\n    endpoint: \"http:\u002F\u002Flocalhost:4566\",\n    region: \"us-east-1\",\n    credentials: { accessKeyId: \"test\", secretAccessKey: \"test\" },\n});\n\nawait client.send(\n    new SendMessageCommand({\n        QueueUrl: \"http:\u002F\u002Flocalhost:4566\u002F000000000000\u002Fdemo-queue\",\n        MessageBody: \"hello from producer\",\n    }),\n);\n\nconsole.log(\"Message sent\");\n```\n\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>\u003Cstrong>Go (AWS SDK v2)\u003C\u002Fstrong>\u003C\u002Fsummary>\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"log\"\n    \"strings\"\n\n    \"github.com\u002Faws\u002Faws-sdk-go-v2\u002Faws\"\n    \"github.com\u002Faws\u002Faws-sdk-go-v2\u002Fconfig\"\n    \"github.com\u002Faws\u002Faws-sdk-go-v2\u002Fcredentials\"\n    \"github.com\u002Faws\u002Faws-sdk-go-v2\u002Fservice\u002Fs3\"\n)\n\nfunc main() {\n    cfg, err := config.LoadDefaultConfig(context.TODO(),\n        config.WithRegion(\"us-east-1\"),\n        config.WithCredentialsProvider(\n            credentials.NewStaticCredentialsProvider(\"test\", \"test\", \"\"),\n        ),\n        config.WithBaseEndpoint(\"http:\u002F\u002Flocalhost:4566\"),\n    )\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    client := s3.NewFromConfig(cfg, func(o *s3.Options) {\n        o.UsePathStyle = true\n    })\n\n    _, err = client.CreateBucket(context.TODO(), &s3.CreateBucketInput{\n        Bucket: aws.String(\"demo-bucket\"),\n    })\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    _, err = client.PutObject(context.TODO(), &s3.PutObjectInput{\n        Bucket: aws.String(\"demo-bucket\"),\n        Key:    aws.String(\"demo.txt\"),\n        Body:   strings.NewReader(\"hello from floci\"),\n    })\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    out, err := client.ListObjectsV2(context.TODO(), &s3.ListObjectsV2Input{\n        Bucket: aws.String(\"demo-bucket\"),\n    })\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    if len(out.Contents) > 0 {\n        fmt.Println(*out.Contents[0].Key)\n    }\n}\n```\n\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>\u003Cstrong>Rust (AWS SDK)\u003C\u002Fstrong>\u003C\u002Fsummary>\n\n```rust\nuse aws_sdk_secretsmanager::config::{Credentials, Region};\nuse aws_sdk_secretsmanager::Client;\n\n#[tokio::main]\nasync fn main() -> Result\u003C(), Box\u003Cdyn std::error::Error>> {\n    let config = aws_config::defaults(aws_config::BehaviorVersion::latest())\n        .region(Region::new(\"us-east-1\"))\n        .credentials_provider(Credentials::new(\"test\", \"test\", None, None, \"floci\"))\n        .endpoint_url(\"http:\u002F\u002Flocalhost:4566\")\n        .load()\n        .await;\n\n    let client = Client::new(&config);\n\n    client\n        .create_secret()\n        .name(\"demo\u002Fsecret\")\n        .secret_string(\"hello from floci\")\n        .send()\n        .await?;\n\n    let secret = client\n        .get_secret_value()\n        .secret_id(\"demo\u002Fsecret\")\n        .send()\n        .await?;\n\n    println!(\"{}\", secret.secret_string().unwrap());\n\n    Ok(())\n}\n```\n\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>\u003Cstrong>Bash (AWS CLI)\u003C\u002Fstrong>\u003C\u002Fsummary>\n\n```bash\nexport AWS_ACCESS_KEY_ID=test\nexport AWS_SECRET_ACCESS_KEY=test\nexport AWS_DEFAULT_REGION=us-east-1\n\ntmp_file=\"$(mktemp)\"\necho \"hello from floci\" > \"$tmp_file\"\n\naws --endpoint-url http:\u002F\u002Flocalhost:4566 s3 mb s3:\u002F\u002Fmy-bucket\naws --endpoint-url http:\u002F\u002Flocalhost:4566 s3 cp \"$tmp_file\" s3:\u002F\u002Fmy-bucket\u002Fdemo.txt\naws --endpoint-url http:\u002F\u002Flocalhost:4566 s3 ls s3:\u002F\u002Fmy-bucket\n\n# Cleanup\naws --endpoint-url http:\u002F\u002Flocalhost:4566 s3 rm s3:\u002F\u002Fmy-bucket\u002Fdemo.txt\nrm -f \"$tmp_file\"\n```\n\n\u003C\u002Fdetails>\n\n---\n\n## Testcontainers\n\nFloci 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.\n\n| Language | Package | Latest | Registry | Source |\n|---|---|---|---|---|\n| Java | `io.floci:testcontainers-floci` | `1.4.0` | [Maven Central](https:\u002F\u002Fmvnrepository.com\u002Fartifact\u002Fio.floci\u002Ftestcontainers-floci) | [GitHub](https:\u002F\u002Fgithub.com\u002Ffloci-io\u002Ftestcontainers-floci) |\n| Node.js | `@floci\u002Ftestcontainers` | `0.1.0` | [npm](https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@floci\u002Ftestcontainers) | [GitHub](https:\u002F\u002Fgithub.com\u002Ffloci-io\u002Ftestcontainers-floci-node) |\n| Python | `testcontainers-floci` | `0.1.1` | [PyPI](https:\u002F\u002Fpypi.org\u002Fproject\u002Ftestcontainers-floci\u002F) | [GitHub](https:\u002F\u002Fgithub.com\u002Ffloci-io\u002Ftestcontainers-floci-python) |\n| Go | — | 🚧 In progress | — | [GitHub](https:\u002F\u002Fgithub.com\u002Ffloci-io\u002Ftestcontainers-floci-go) |\n\n\u003Cdetails>\n\u003Csummary>\u003Cstrong>Java\u003C\u002Fstrong>\u003C\u002Fsummary>\n\nAdd the dependency (Testcontainers 1.x \u002F Spring Boot 3.x):\n\n```xml\n\u003Cdependency>\n    \u003CgroupId>io.floci\u003C\u002FgroupId>\n    \u003CartifactId>testcontainers-floci\u003C\u002FartifactId>\n    \u003Cversion>1.4.0\u003C\u002Fversion>\n    \u003Cscope>test\u003C\u002Fscope>\n\u003C\u002Fdependency>\n```\n\nFor Testcontainers 2.x \u002F Spring Boot 4.x use version `2.5.0`.\n\nBasic usage with JUnit 5:\n\n```java\n@Testcontainers\nclass S3IntegrationTest {\n\n    @Container\n    static FlociContainer floci = new FlociContainer();\n\n    @Test\n    void shouldCreateBucket() {\n        S3Client s3 = S3Client.builder()\n                .endpointOverride(URI.create(floci.getEndpoint()))\n                .region(Region.of(floci.getRegion()))\n                .credentialsProvider(StaticCredentialsProvider.create(\n                        AwsBasicCredentials.create(floci.getAccessKey(), floci.getSecretKey())))\n                .forcePathStyle(true)\n                .build();\n\n        s3.createBucket(b -> b.bucket(\"my-bucket\"));\n\n        assertThat(s3.listBuckets().buckets())\n                .anyMatch(b -> b.name().equals(\"my-bucket\"));\n    }\n}\n```\n\n**Spring Boot** — use `@ServiceConnection` for zero-config auto-wiring:\n\n```java\n@SpringBootTest\n@Testcontainers\nclass AppIntegrationTest {\n\n    @Container\n    @ServiceConnection\n    static FlociContainer floci = new FlociContainer();\n\n    @Autowired\n    S3Client s3;\n\n    @Test\n    void shouldCreateBucket() {\n        s3.createBucket(b -> b.bucket(\"my-bucket\"));\n        assertThat(s3.listBuckets().buckets())\n                .anyMatch(b -> b.name().equals(\"my-bucket\"));\n    }\n}\n```\n\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>\u003Cstrong>Node.js \u002F TypeScript\u003C\u002Fstrong>\u003C\u002Fsummary>\n\n```sh\nnpm install --save-dev @floci\u002Ftestcontainers\n```\n\n```ts\nimport { FlociContainer } from \"@floci\u002Ftestcontainers\";\nimport { S3Client, CreateBucketCommand, ListBucketsCommand } from \"@aws-sdk\u002Fclient-s3\";\n\ndescribe(\"S3\", () => {\n    let floci: FlociContainer;\n\n    beforeAll(async () => {\n        floci = await new FlociContainer().start();\n    });\n\n    afterAll(async () => {\n        await floci.stop();\n    });\n\n    it(\"should create and list a bucket\", async () => {\n        const s3 = new S3Client({\n            endpoint: floci.getEndpoint(),\n            region: floci.getRegion(),\n            credentials: {\n                accessKeyId: floci.getAccessKey(),\n                secretAccessKey: floci.getSecretKey(),\n            },\n            forcePathStyle: true,\n        });\n\n        await s3.send(new CreateBucketCommand({ Bucket: \"my-bucket\" }));\n        const { Buckets } = await s3.send(new ListBucketsCommand({}));\n        expect(Buckets?.some(b => b.Name === \"my-bucket\")).toBe(true);\n    });\n});\n```\n\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>\u003Cstrong>Python\u003C\u002Fstrong>\u003C\u002Fsummary>\n\n```sh\npip install testcontainers-floci\n```\n\n```python\nimport boto3\nfrom testcontainers_floci import FlociContainer\n\ndef test_s3_create_bucket():\n    with FlociContainer() as floci:\n        s3 = boto3.client(\n            \"s3\",\n            endpoint_url=floci.get_endpoint(),\n            region_name=floci.get_region(),\n            aws_access_key_id=floci.get_access_key(),\n            aws_secret_access_key=floci.get_secret_key(),\n        )\n        s3.create_bucket(Bucket=\"my-bucket\")\n        buckets = s3.list_buckets()[\"Buckets\"]\n        assert any(b[\"Name\"] == \"my-bucket\" for b in buckets)\n```\n\nPytest fixture style:\n\n```python\nimport pytest\nimport boto3\nfrom testcontainers_floci import FlociContainer\n\n@pytest.fixture(scope=\"session\")\ndef floci():\n    with FlociContainer() as container:\n        yield container\n\ndef test_s3_create_bucket(floci):\n    s3 = boto3.client(\n        \"s3\",\n        endpoint_url=floci.get_endpoint(),\n        region_name=floci.get_region(),\n        aws_access_key_id=floci.get_access_key(),\n        aws_secret_access_key=floci.get_secret_key(),\n    )\n    s3.create_bucket(Bucket=\"my-bucket\")\n    buckets = s3.list_buckets()[\"Buckets\"]\n    assert any(b[\"Name\"] == \"my-bucket\" for b in buckets)\n```\n\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>\u003Cstrong>Go\u003C\u002Fstrong>\u003C\u002Fsummary>\n\nGo support is in progress. Track it at [testcontainers-floci-go](https:\u002F\u002Fgithub.com\u002Ffloci-io\u002Ftestcontainers-floci-go).\n\n\u003C\u002Fdetails>\n\n---\n\n## Compatibility Testing\n\n> For full compatibility validation against real SDK and client workflows, see the [compatibility-tests](.\u002Fcompatibility-tests\u002F) directory.\n\nThis 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.\n\n| Module | Language \u002F Tool | SDK \u002F Client \u002F Version | Tests |\n|---|---|---|---:|\n| `sdk-test-java` | Java 17 | AWS SDK for Java v2 | 889 |\n| `sdk-test-node` | Node.js | AWS SDK for JavaScript v3 | 360 |\n| `sdk-test-python` | Python 3 | boto3 | 264 |\n| `sdk-test-go` | Go | AWS SDK for Go v2 | 136 |\n| `sdk-test-awscli` | Bash | AWS CLI v2 | 145 |\n| `sdk-test-rust` | Rust | AWS SDK for Rust | 86 |\n| `compat-terraform` | Terraform | v1.10+ | 14 |\n| `compat-opentofu` | OpenTofu | v1.9+ | 14 |\n| `compat-cdk` | AWS CDK | v2+ | 17 |\n\n**1,850+ automated compatibility tests across 6 SDKs and 3 IaC tools.**\n\n---\n\n## Migrating from LocalStack\n\nFloci 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.\n\n```yaml\n# Before\nimage: localstack\u002Flocalstack\n\n# After — no init scripts, or scripts that don't call aws \u002F boto3\nimage: floci\u002Ffloci:latest\n\n# After — init scripts that use aws CLI or boto3\nimage: floci\u002Ffloci:latest-compat   # includes Python 3, AWS CLI, boto3 pre-configured\n```\n\n**LocalStack environment variables are translated automatically** — no renaming required:\n\n| LocalStack | Floci equivalent |\n|---|---|\n| `LOCALSTACK_HOST` | `FLOCI_HOSTNAME` |\n| `PERSISTENCE=1` | `FLOCI_STORAGE_MODE=persistent` |\n| `LAMBDA_DOCKER_NETWORK` | `FLOCI_SERVICES_LAMBDA_DOCKER_NETWORK` |\n| `LAMBDA_REMOVE_CONTAINERS=1` | `FLOCI_SERVICES_LAMBDA_EPHEMERAL=true` |\n| `DEBUG=1` | `QUARKUS_LOG_LEVEL=DEBUG` |\n\nInit scripts mounted under `\u002Fetc\u002Flocalstack\u002Finit\u002F` run unchanged. The `\u002F_localstack\u002Finit` and `\u002F_localstack\u002Fhealth` endpoints are still served. Set `LOCALSTACK_PARITY=false` to opt out of the automatic translation.\n\n→ [Full migration guide](https:\u002F\u002Ffloci.io\u002Ffloci\u002Fgetting-started\u002Fmigrate-from-localstack\u002F)\n\n---\n\n## Image Tags\n\nEvery tag combines two choices: **variant** (what's inside) and **channel** (how stable).\n\n|  | Standard | Compat (+ AWS CLI + boto3) |\n|---|---|---|\n| **Release (latest)** | `latest` ✅ | `latest-compat` |\n| **Release (pinned)** | `x.y.z` | `x.y.z-compat` |\n| **Nightly (floating)** | `nightly` | `nightly-compat` |\n| **Nightly (dated)** | `nightly-mmddyyyy` | `nightly-mmddyyyy-compat` |\n\n- **Standard** — GraalVM native binary. ~24 ms startup, ~40 MB image, ~13 MiB idle memory.\n- **Compat** — Extends the standard image with Python 3, AWS CLI, and boto3. Same startup and memory, larger image.\n- **Release** — Published on every stable version tag.\n- **Nightly** — Built every night at 22:00 CT from `main`. Dated tags (e.g. `nightly-05022026`) are fixed; `nightly` always points to the latest.\n\n```yaml\n# Recommended\nimage: floci\u002Ffloci:latest\n\n# With AWS CLI + boto3\nimage: floci\u002Ffloci:latest-compat\n\n# Pinned\nimage: floci\u002Ffloci:1.5.11\n\n# Track main\nimage: floci\u002Ffloci:nightly\n```\n\n---\n\n## Configuration\n\nAll settings are overridable via environment variables (`FLOCI_` prefix).\n\n| Variable | Default | Description |\n|---|---|---|\n| `FLOCI_PORT` | `4566` | Port exposed by the Floci API |\n| `FLOCI_DEFAULT_REGION` | `us-east-1` | Default AWS region |\n| `FLOCI_DEFAULT_ACCOUNT_ID` | `000000000000` | Default AWS account ID |\n| `FLOCI_BASE_URL` | `http:\u002F\u002Flocalhost:4566` | Base URL used when Floci returns service URLs (e.g. SQS QueueUrl) |\n| `FLOCI_HOSTNAME` | *(unset)* | Hostname to use in returned URLs when Floci runs inside Docker Compose |\n| `FLOCI_STORAGE_MODE` | `memory` | Controls how data is stored: `memory` · `persistent` · `hybrid` · `wal` |\n| `FLOCI_STORAGE_PERSISTENT_PATH` | `.\u002Fdata` | Directory used for persisted state |\n| `FLOCI_ECR_BASE_URI` | `public.ecr.aws` | AWS ECR base URI used when pulling container images (e.g. Lambda) |\n\n- Full reference: [configuration docs](https:\u002F\u002Ffloci.io\u002Ffloci\u002Fconfiguration\u002Fapplication-yml\u002F)\n- Per-service storage overrides: [storage docs](https:\u002F\u002Ffloci.io\u002Ffloci\u002Fconfiguration\u002Fstorage\u002F#per-service-storage-overrides)\n\n**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:\n\n```yaml\nservices:\n  floci:\n    image: floci\u002Ffloci:latest\n    ports:\n      - \"4566:4566\"\n    environment:\n      - FLOCI_HOSTNAME=floci  # URLs will use http:\u002F\u002Ffloci:4566\u002F...\n  my-app:\n    environment:\n      - AWS_ENDPOINT_URL=http:\u002F\u002Ffloci:4566\n    depends_on:\n      - floci\n```\n\nWithout this, SQS returns `http:\u002F\u002Flocalhost:4566\u002F...` in QueueUrl responses, which resolves to the wrong container.\n\n---\n\n## Star history\n\n[![Star History Chart](https:\u002F\u002Fapi.star-history.com\u002Fsvg?repos=floci-io\u002Ffloci&type=Date)](https:\u002F\u002Fstar-history.com\u002F#floci-io\u002Ffloci&Date)\n\n---\n\n## Contributors\n\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Ffloci-io\u002Ffloci\u002Fgraphs\u002Fcontributors\">\n  \u003Cimg src=\"https:\u002F\u002Fcontrib.rocks\u002Fimage?repo=floci-io\u002Ffloci\" \u002F>\n\u003C\u002Fa>\n\n---\n\n## License\n\nMIT — use it however you want.\n","Floci 是一个免费且开源的本地 AWS 服务模拟器。它支持通过简单的 `docker compose up` 命令启动，无需 AWS 账户或任何功能限制。项目基于 Java 开发，能够仿真包括 S3、SQS、EC2 等在内的多种 AWS 服务，并且与 Docker 和 Testcontainers 集成良好，方便开发者在本地环境中进行开发和测试工作。特别适用于需要频繁与 AWS 交互但又希望减少云端依赖性和成本的软件开发团队。此外，Floci 还提供了多账户隔离和支持 SDK 直接集成等特性，进一步增强了其灵活性和实用性。",2,"2026-06-11 03:50:08","high_star"]