Floci (LocalStack alternative) storage modes: pick the right tradeoff per service (and never pay for it)
Source: Dev.to
Overview
State that survives a docker compose down is one of those things you don’t think about—until your test suite needs it, your local dev needs it, and your CI pipeline absolutely doesn’t.
Floci ships four storage modes (all free, all in core) with per‑service overrides, letting you pick the right trade‑off for the job.
Storage modes
| Mode | Survives restart | Write behavior | Best for |
|---|---|---|---|
| memory | ❌ | Pure RAM | CI, unit tests, ephemeral integration tests |
| hybrid | ✅ | Async flush to disk | Local development (the sweet spot) |
| persistent | ✅ | Sync write on every change | “Don’t lose my last write” workflows |
| wal | ✅ | Append‑only log + compaction | High‑throughput durable workloads |
You set a global default and override per service when a different behavior is required.
Configuration examples
Memory (default) – ideal for CI
# docker-compose.yml
services:
floci:
image: floci/floci:latest
ports:
- "4566:4566"
environment:
FLOCI_STORAGE_MODE: memory
Everything stays in RAM. Container restarts wipe the slate. Fastest possible writes, smallest footprint.
Hybrid – local development
# docker-compose.yml
services:
floci:
image: floci/floci:latest
ports:
- "4566:4566"
volumes:
- ./data:/app/data
environment:
FLOCI_STORAGE_MODE: hybrid
Reads and writes hit memory; a background flush moves data to disk every ~5 seconds. docker‑compose down doesn’t nuke your seeded test data.
Persistent – when losing the last write hurts
# docker-compose.yml
services:
floci:
image: floci/floci:latest
ports:
- "4566:4566"
volumes:
- ./data:/app/data
environment:
FLOCI_STORAGE_MODE: persistent
Every change syncs to disk before responding. Slower writes, but acknowledged data is genuinely on disk—even if Docker hard‑kills the container.
WAL – high‑write workloads that still need durability
# docker-compose.yml
services:
floci:
image: floci/floci:latest
ports: ["4566:4566"]
volumes:
- ./data:/app/data
environment:
FLOCI_STORAGE_MODE: wal
FLOCI_STORAGE_WAL_COMPACTION_INTERVAL_MS: 30000
Mutations go to an append‑only log first, with periodic compaction. You get durability without the random‑write cost of the persistent mode.
Global default with per‑service overrides
# docker-compose.yml
services:
floci:
image: floci/floci:latest
ports:
- "4566:4566"
volumes:
- ./data:/app/data
environment:
FLOCI_STORAGE_MODE: memory # everything is ephemeral by default
FLOCI_STORAGE_SERVICES_DYNAMODB_MODE: persistent # keep DynamoDB on disk
FLOCI_STORAGE_SERVICES_S3_MODE: hybrid # keep S3 buckets across restarts
Fast tests overall, but retain seeded DynamoDB tables and S3 buckets across restarts.
Comparison with LocalStack (Pro)
| Feature | LocalStack (Pro) | Floci |
|---|---|---|
| Cost | Paid tier | Free, MIT‑licensed |
| Granularity | Global on/off | Four modes, per‑service overrides |
| Write strategy | Snapshots (point‑in‑time) | Sync, async, or WAL — your choice |
| During snapshot | Service is locked, requests block | No locking, writes never pause |
| Cross‑version | Snapshots may break across versions | Plain on‑disk format |
| Implementation | Python pickle serialization | Native, format per service |
The locking part is the one most people don’t anticipate. LocalStack’s snapshot mechanism blocks requests while a service is being saved—acceptable at shutdown but surprising mid‑test. Floci never pauses writes; durability comes from the chosen storage mode, not from a freeze‑and‑dump.
Typical setups
CI
services:
floci:
image: floci/floci:latest
ports:
- "4566:4566"
environment:
FLOCI_STORAGE_MODE: memory
Local development
services:
floci:
image: floci/floci:latest
ports:
- "4566:4566"
volumes:
- ./data:/app/data
environment:
FLOCI_STORAGE_MODE: hybrid
No auth token, no Pro tier, no surprise locking. Persistence is a basic developer ergonomic, not an enterprise‑only feature.
Links
- 🔗 https://github.com/floci-io/floci
- 📚 Storage documentation (link in repo)
- 💬 Community Slack: https://floci.slack.com