https://github.com/yoavgeva/ferricstore
Distributed crash-safe key-value store with Redis wire protocol. Durable by default — every write is Raft-committed and fsync'd. Embeddable Elixir library or standalone server. Built with Elixir + Rust NIFs.
https://github.com/yoavgeva/ferricstore
acid bitcask cache distributed-systems elixir key-value-store raft redis resp3 rust
Last synced: about 2 months ago
JSON representation
Distributed crash-safe key-value store with Redis wire protocol. Durable by default — every write is Raft-committed and fsync'd. Embeddable Elixir library or standalone server. Built with Elixir + Rust NIFs.
- Host: GitHub
- URL: https://github.com/yoavgeva/ferricstore
- Owner: yoavgeva
- Created: 2026-03-15T22:37:10.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2026-04-26T08:26:30.000Z (about 2 months ago)
- Last Synced: 2026-04-26T08:34:38.708Z (about 2 months ago)
- Topics: acid, bitcask, cache, distributed-systems, elixir, key-value-store, raft, redis, resp3, rust
- Language: Elixir
- Size: 44 MB
- Stars: 8
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# FerricStore
[](https://hex.pm/packages/ferricstore)
[](https://hexdocs.pm/ferricstore)
[](https://github.com/yoavgeva/ferricstore/actions/workflows/test.yml)
[](https://opensource.org/licenses/MIT)
**The Redis-compatible store where every write is durable by default.**
FerricStore is a distributed, crash-safe key-value store with Redis wire protocol (RESP3). Every write goes through Raft consensus and is fsync'd to disk before the client gets OK. No "enable persistence" checkbox. No "hope the AOF rewrite finishes before the crash." Your data survives kill -9, node failures, and power loss — automatically.
## Why FerricStore?
Redis, Dragonfly, and Memcached treat persistence as optional. By default, your data lives only in RAM. Enable AOF? You still lose the last second. Enable RDB snapshots? You lose minutes. Even with replication, failover is manual or requires Sentinel — a separate system to babysit your cache.
You shouldn't have to choose between speed and safety.
Every write in FerricStore is:
| Property | How |
|---|---|
| **Atomic** | Each command is a single Raft log entry — applied or not, never partial |
| **Consistent** | Raft linearizability — every read sees the latest committed write |
| **Isolated** | Single-threaded state machine per shard — commands never interleave |
| **Durable** | WAL + fdatasync + Raft quorum — majority of nodes must persist before ack |
Not every key needs the same guarantee. FerricStore lets you choose per namespace:
```elixir
# Session tokens: never lose them (quorum — majority must persist before ack)
FERRICSTORE.CONFIG SET "session:" durability quorum
# Cache entries: speed over safety (async — write to local WAL, replicate in background)
FERRICSTORE.CONFIG SET "cache:" durability async
```
One cluster. Mixed workloads. The right tradeoff for each key prefix.
## Beyond Cachex and Nebulex
If you're using Cachex or Nebulex today, FerricStore gives you:
- **Crash survival** — your cache survives restarts, deploys, and kill -9. ETS doesn't.
- **Disk-backed eviction** — when RAM fills up, evicted keys are read from disk instead of hitting your database again. Less load on your database, fewer cache stampedes.
- **No cold start** — restart your app, all data is already on disk. No thundering herd while the cache warms up.
- **Redis protocol** — non-Elixir services can share the same store. Use any Redis client library.
- **Data structures beyond key-value** — Hash, List, Set, SortedSet, Stream, Geo, JSON, Bitmap, HyperLogLog, Bloom, Cuckoo, Count-Min Sketch, TopK, TDigest.
- **Automatic failover** — Raft consensus with leader election. No Sentinel, no manual intervention.
- **Mixed durability** — quorum (crash-safe) or async (fast) per key prefix in the same cluster.
## Quick Start
### Embedded (inside your Elixir app)
```elixir
# mix.exs
{:ferricstore, "~> 0.3.0"}
```
```elixir
# Durable by default — this write survives kill -9
:ok = FerricStore.set("user:42:name", "alice", ttl: :timer.hours(1))
{:ok, "alice"} = FerricStore.get("user:42:name")
# Atomic compare-and-swap
{:ok, true} = FerricStore.cas("counter", "1", "2")
# Distributed lock
{:ok, true} = FerricStore.lock("resource:42", "owner-id", ttl: 30_000)
```
No sidecar. No Docker. No ops. Your Phoenix app starts, FerricStore starts with it.
### Standalone (Redis-compatible server)
```bash
docker run -p 6379:6379 -e FERRICSTORE_PROTECTED_MODE=false -v ferricstore_data:/data yoavgeva/ferricstore
# Connect with any Redis client
redis-cli -p 6379
127.0.0.1:6379> SET user:42:name alice
OK
```
Drop-in Redis replacement. 250+ commands. Use your existing Redis client libraries.
## Guides
- [Getting Started](guides/getting-started.md) — installation, configuration, first commands
- [Best Practices](guides/best-practices.md) — hash tags, durability, pipelining, key design
- [Architecture](guides/architecture.md) — write path, read path, three-tier storage, Raft consensus
- [Commands Reference](guides/commands.md) — all 250+ commands with syntax and compatibility notes
- [Embedded Mode](guides/embedded-mode.md) — using FerricStore inside your Elixir app
- [Standalone Mode](guides/standalone-mode.md) — Redis-compatible server, dashboard, Prometheus
- [Configuration](guides/configuration.md) — all config options
- [Deployment](guides/deployment.md) — Docker, Kubernetes, bare metal, clustering
- [Security](guides/security.md) — ACL, TLS, protected mode
- [Extensions](guides/extensions.md) — Plug sessions, Ecto L2 cache
- [Comparison](guides/comparison.md) — vs Redis, Valkey, Dragonfly, Garnet, Kvrocks, Cachex, Nebulex
## Requirements
- Elixir >= 1.19
- Erlang/OTP 28+
- Rust toolchain (for NIF compilation, or use precompiled binaries)
## License
MIT