Search, vectors, graph, SPARQL, transactions, and real-time CDC on the same tables — not separate stores. CQL compatible. Cypher + Bolt v5. SPARQL 1.1. Strict serializable transactions via Accord. Your data lives in S3 — nodes recover in seconds. Rust-native, zero GC pauses. Start on a single node, scale to a full production cluster — same binary, same config, no migration.
The Problem
Pull up your cloud bill. Look past the compute, past the live storage. The largest line items are EBS snapshots, cross-region replicas, and backup retention — copies of data that nobody reads, nobody queries, and nobody thinks about until something goes wrong. It's the most expensive insurance policy in your infrastructure, and it scales with every gigabyte you store.
Point-in-time recovery requires EBS snapshots — a full second copy of your dataset that exists only for "just in case." 10 TB with 30-day retention costs $2,250/month in snapshots alone — on top of the $3,000–7,500/month you're already paying for the live EBS volumes. A year of retention? $15,000/month. That's $180,000/year for data you hope you never need to read.
Once on the live EBS volume. Once in EBS snapshots for recovery. Once more if you replicate across regions. At petabyte scale with RF=3, you're storing 3 PB on EBS ($300K/month), snapshotting 3 PB ($150K/month), and none of that snapshot storage serves a single read.
Java's garbage collector causes unpredictable tail latency spikes. No amount of JVM tuning eliminates the problem — it just moves it.
When a node dies, streaming hundreds of gigabytes from replicas takes hours. Your cluster runs degraded the entire time.
Compaction tuning, repair scheduling, bootstrap orchestration, heap sizing — Cassandra demands a dedicated team to keep it healthy.
Core Capabilities
One database for AI-native workloads. Search, vectors, graph, SPARQL, transactions, and CDC — unified on S3.
That $2,250/month you're spending on EBS snapshots for 10 TB? That $180,000/year insurance policy? Ferrosa makes it $2.30/month. Not because we compress better or found cheaper storage — because the backup step doesn't exist. Your data is already durable in S3. Point-in-time recovery is just keeping commit log segments longer, and S3 Lifecycle rules tier them to Glacier automatically.
One command sets your retention policy:
ferrosa-ctl storage retention set --years 1.
Ferrosa configures S3 Lifecycle rules that tier your archives through Standard,
Infrequent Access, and Glacier automatically. A full year of point-in-time recovery
costs ~$45/TB — actually cheaper than 3 months without tiering, because data
spends most of its life in Deep Archive at $0.00099/GB.
| 10 TB Recovery | Cassandra | Ferrosa |
|---|---|---|
| 7 days | $525/mo | $0.55/mo |
| 30 days | $2,250/mo | $2.30/mo |
| 1 year | $15,000/mo | $3.75/mo |
| 3 years | $30,000/mo | $5.20/mo |
Cassandra: EBS snapshots at $0.05/GB, 5% daily change rate, RF=3. Ferrosa: S3 Lifecycle tiered commit log retention.
Durable storage lives in S3. Local NVMe is a hot cache, not a commitment. Nodes are ephemeral — lose one, spin up a replacement, and it's serving reads from S3 in seconds instead of streaming for hours.
NVMe is a bounded cache layer, S3 is the unbounded durable store. Data that doesn't
fit on NVMe lives in S3 and gets pulled through on demand. The
local_cache_max_bytes config controls how much
NVMe is used. Size your local disks for your working set, not your total dataset.
Point-in-time recovery retention is one command:
ferrosa-ctl storage retention set --years 1.
Ferrosa configures S3 Lifecycle rules that tier your commit log archives through
Standard, Infrequent Access, and Glacier automatically. A full year of point-in-time
recovery costs ~$45/TB — cheaper than 3 months without tiering. Cold SSTables transition to
cheaper storage classes automatically while staying instantly readable through
the block cache — 66% savings on storage with zero performance impact.
Node retirement is just as simple: decommission a node and its S3 objects are
tagged for cleanup.
Works with AWS S3, MinIO, Cloudflare R2, or any S3-compatible endpoint. No vendor lock-in.
S3: ~$0.023/GB/mo · 1yr recovery: ~$45/TB · SSTable tiering: 66% savingsNo JVM. No garbage collector. No stop-the-world pauses. Lock-free reads via ArcSwap, sharded memtables with nanosecond-level write locks, async I/O on Tokio. Predictable latency from the first request to the billionth.
P99 latency: no GC tailCQL protocol v4 and v5 — the same wire protocol your drivers already speak. Python, Java, Go, Rust (cdrs-tokio), and Node.js drivers connect without code changes. DDL, DML, prepared statements, batch operations, lightweight transactions (IF NOT EXISTS, IF conditions), system keyspaces, ALLOW FILTERING, toJson(), counter increment/decrement, collection types (map, set, list) with full UPDATE +/- operators and collection bind values in prepared statements — all there.
CQL v4/v5 · Bolt v5 · SPARQL 1.1 · 0 driver changes requiredFull Cypher and SPARQL 1.1 query engines on your CQL tables. No separate graph database. Vertices and edges are normal tables with schema extensions. Variable-length paths, aggregations, expression evaluation, and worst-case optimal joins via leapfrog triejoin for cyclic pattern matching. Bolt v5 wire protocol for Neo4j drivers, HTTP/JSON for Cypher, and W3C SPARQL Protocol for semantic web and RDF workloads.
Cypher · SPARQL 1.1 · Bolt v5 · HTTP/JSON · RDF* · property pathsSUBSCRIBE to any CQL or Cypher query for real-time change streaming. Interval polling with EVERY, or push-on-write with DELTA mode. No external Kafka, Debezium, or CDC connector pipeline needed — change data capture is built into the storage engine.
Fully backward compatible with existing CQL drivers. Subscribe to tables, graph traversals, or observability views with the same syntax.
SUBSCRIBE social.users EVERY 5s-- Poll for changes every 5 seconds SUBSCRIBE social.users EVERY 5s; -- Push changes as they happen SUBSCRIBE social.users DELTA; -- Subscribe to a graph traversal SUBSCRIBE MATCH (a:Person)-[:FOLLOWS]->(b) RETURN b.name EVERY 10s;
Eleven index types behind a single trait: B-tree for range scans, hash for O(1) lookups,
composite for multi-column queries, phonetic for fuzzy string matching (Soundex,
Metaphone, Double Metaphone, Caverphone), two vector methods for approximate nearest
neighbor search, filtered indexes with predicates, and full-text search with
BM25 ranked retrieval. Native vector<float, N> CQL type
for embedding storage — store and query high-dimensional vectors directly.
Indexes are storage-attached — built asynchronously after SSTable flush with zero
impact on the write path. Full-text indexes use inverted-index sidecar files with
a pluggable analyzer pipeline (tokenizer, stop words, Porter stemmer).
Per-index staleness tracking and operational metrics
via system_views.secondary_indexes let you monitor build progress
and lag in real time. CQL-compatible DDL with standard CREATE INDEX ... USING 'type' syntax.
-- B-tree index for range queries CREATE INDEX idx_email ON users (email) USING 'btree'; -- Phonetic index for fuzzy name matching CREATE INDEX idx_name ON users (last_name) USING 'phonetic' WITH OPTIONS = {'algorithm': 'double_metaphone'}; -- Vector index for ANN search CREATE INDEX idx_embed ON documents (embedding) USING 'vector' WITH OPTIONS = {'method': 'hnsw', 'metric': 'cosine', 'dimensions': '768'}; -- Full-text search with BM25 ranking CREATE INDEX idx_body ON articles (body) USING 'fulltext'; SELECT * FROM articles WHERE fts_match(body, 'distributed AND database'); -- Nearest neighbor query SELECT * FROM documents ORDER BY embedding ANN OF [0.1, 0.2, ...] LIMIT 10;
Distributed transactions with strict serializability via the Accord consensus protocol — not Paxos, not 2PC. Multi-partition atomic operations with all-or-nothing semantics. INSERT IF NOT EXISTS, UPDATE/DELETE IF conditions, and batch compare-and-set all work out of the box. Cross-shard transactions coordinate automatically.
1-RTT fast path through leaseholder for low-latency commits. 2-RTT slow path when coordination is needed. Crash recovery via protocol log replay with .accord sidecar files. Dynamic electorate reconfiguration with a 4-gate join protocol for safe membership changes.
Accord protocol · strict serializable · 1-RTT fast path · Jepsen-verifiedVerified with Jepsen-style chaos testing across partition, kill, pause, and clock-skew fault injection.
-- Lightweight transactions (Cassandra-compatible) INSERT INTO accounts (id, balance) VALUES ('acct-1', 1000) IF NOT EXISTS; -- Conditional update with compare-and-set UPDATE accounts SET balance = 900 WHERE id = 'acct-1' IF balance = 1000; -- Multi-statement transaction BEGIN TRANSACTION UPDATE accounts SET balance = balance - 100 WHERE id = 'acct-1' IF balance >= 100; UPDATE accounts SET balance = balance + 100 WHERE id = 'acct-2'; COMMIT TRANSACTION;
Pin hot tables to local NVMe for sub-millisecond reads. A single table attribute
(storage.pin = nvme) keeps SSTables on local disk, bypassing S3 entirely.
Ideal for session caches, materialized views, and lookup tables that tolerate node loss.
Optional pin_max_bytes cap evicts oldest SSTables when the budget is exceeded.
ALTER TABLE toggles pin mode on live tables — unpinning automatically uploads
existing SSTables to S3.
Built-in inverted index with BM25 ranked retrieval — no external search engine needed. Create a full-text index on any text column and query with boolean operators (AND, OR, NOT), phrase matching, and prefix wildcards. Pluggable analyzer pipeline: tokenizer, stop-word filter, Porter stemmer. Sidecar index files are built on flush and merged during compaction — zero write-path overhead.
BM25 ranking · AND/OR/NOT/prefix · pluggable analyzers · zero write overheadReaders never block. ArcSwap provides wait-free atomic view loading. Writers touch sharded memtables for nanoseconds. No global locks, no contention, no coordination overhead on the hot path.
wait-free reads · zero contention
Self-hosted distributed tracing, metrics, and query analysis — no external
tools required. 25+ tracing spans across CQL, consensus, storage, and network
paths. Slow query detection with parameterized logging. Query fingerprint
tracking for automatic optimization recommendations. Per-client billing
metering. On-demand flame charts for CPU hot path analysis. All data in
system_observability virtual tables, queryable via standard CQL.
Optional OTLP export for enterprise monitoring stacks.
5-node clusters with Raft consensus, 8 tunable consistency levels (ONE through ALL, LOCAL_ONE, LOCAL_QUORUM, EACH_QUORUM), and hinted handoff for replica failure recovery. Operator-controlled node join with approval gate, graceful decommission with streaming protocol, and skew-aware token rebalancing. Background maintenance handles auto-flush, compaction, and commit log GC. Ships as a systemd service with .deb packaging and Docker Compose support.
Raft · tunable CL · hinted handoff · token rebalancingAutomatic reconnection with exponential backoff for internode links. Graceful drain with configurable timeout ensures in-flight requests complete before shutdown. Connection drop detection and per-connection request limiting provide backpressure under load. Production-quality code built to handle real-world failure scenarios.
auto-reconnect · graceful drain · backpressureWhen a replica is temporarily unavailable, writes are stored as hints and replayed automatically when the node recovers. Configurable hint window and TTL ensure data consistency without manual repair for transient failures.
auto hint storage · replay on recoveryOperator-controlled join with approval gate prevents accidental cluster changes. Graceful decommission streams data to remaining nodes before removal. Token rebalancing with skew-aware algorithm redistributes load evenly across the ring.
join · decommission · rebalance
Native /metrics endpoint exposes cluster health, query latencies,
storage utilization, and connection counts in Prometheus format. No sidecar exporter
needed — scrape directly from each Ferrosa node. Integrates with Grafana, Datadog,
and any Prometheus-compatible monitoring stack.
User-defined functions execute as sandboxed WebAssembly — no Java, no JavaScript. Upload a compiled WASM binary to a table, reference it in CREATE FUNCTION with an AS clause. Write functions in Rust (preferred), C, Go, or any language that compiles to WASM. Full Wasmtime integration with WIT contract, compilation caching, and sandbox enforcement. Memory-limited, CPU-time-limited, no network or filesystem access. Deterministic execution guaranteed.
WASM sandbox · WIT contract · Wasmtime compilation · moka cache · UDF + UDASee It In Action
Your existing application code works unchanged. Just point your driver at Ferrosa.
-- Create a keyspace with S3-backed replication CREATE KEYSPACE social WITH replication = { 'class': 'SimpleStrategy', 'replication_factor': 3 }; -- Tables work exactly like Cassandra CREATE TABLE social.users ( user_id uuid PRIMARY KEY, name text, email text, created_at timestamp ); -- Inserts, selects, updates — all standard CQL INSERT INTO social.users (user_id, name, email, created_at) VALUES (uuid(), 'Alice', 'alice@example.com', toTimestamp(now())); SELECT * FROM social.users WHERE user_id = ?;
-- Graph queries on the same data — no separate database -- Mark tables as graph entities via schema extensions ALTER TABLE social.users WITH extensions = {'graph.type': 'vertex', 'graph.label': 'Person'}; ALTER TABLE social.follows WITH extensions = { 'graph.type': 'edge', 'graph.label': 'FOLLOWS', 'graph.source': 'Person', 'graph.target': 'Person' }; -- Then query with Cypher via HTTP/JSON endpoint MATCH (a:Person {name: 'Alice'})-[:FOLLOWS]->(b:Person) RETURN b.name, b.email; -- Multi-hop: friends of friends MATCH (a:Person)-[:FOLLOWS*2]->(c:Person) WHERE a.name = 'Alice' RETURN DISTINCT c.name;
# SPARQL 1.1 — semantic queries on the same data # W3C standard for RDF, knowledge graphs, and provenance PREFIX foaf: <http://xmlns.com/foaf/0.1/> # Find all people and who they know SELECT ?person ?friend WHERE { ?person foaf:name ?name . ?person foaf:knows ?friend . } ORDER BY ?name LIMIT 20 # Property paths — transitive closure (who can Alice reach?) SELECT DISTINCT ?reachable WHERE { <http://example.org/alice> foaf:knows+ ?reachable . } # RDF* annotations — provenance on edges SELECT ?who ?confidence WHERE { << ?s foaf:knows ?o >> <http://example.org/confidence> ?confidence . FILTER(?confidence > 0.8) } # INSERT DATA — write triples via SPARQL Update INSERT DATA { <http://example.org/bob> foaf:name "Bob" . <http://example.org/bob> foaf:knows <http://example.org/alice> . }
-- B-tree index for sorted range queries CREATE INDEX idx_email ON social.users (email) USING 'btree'; -- Hash index for O(1) equality lookups CREATE INDEX idx_uid ON social.users (user_id) USING 'hash'; -- Composite index on multiple columns CREATE INDEX idx_name ON social.users (last_name, first_name) USING 'composite'; -- Phonetic index — fuzzy name matching CREATE INDEX idx_snd ON social.users (last_name) USING 'phonetic' WITH OPTIONS = {'algorithm': 'double_metaphone'}; SELECT * FROM social.users WHERE last_name SOUNDS LIKE 'Smith'; -- Filtered index — partial index over a row subset CREATE INDEX idx_active ON social.users (email) USING 'btree' WHERE status = 'active'; -- Vector index with HNSW for ANN search CREATE INDEX idx_embed ON docs.articles (embedding) USING 'vector' WITH OPTIONS = {'method': 'hnsw', 'metric': 'cosine', 'dimensions': '768', 'm': '16', 'ef_construction': '200'}; SELECT * FROM docs.articles ORDER BY embedding ANN OF [0.1, 0.2, ...] LIMIT 10; -- Monitor index health SELECT index_name, status, lag_seconds FROM system_views.secondary_indexes;
# Your existing Python code — just change the contact point from cassandra.cluster import Cluster # Before: Cassandra # cluster = Cluster(['cassandra-node-1.prod']) # After: Ferrosa — same driver, same API cluster = Cluster(['ferrosa-node-1.prod']) session = cluster.connect('social') # Prepared statements work identically stmt = session.prepare(""" SELECT name, email FROM users WHERE user_id = ? """) user = session.execute(stmt, [user_id]) print(user.one().name) # Batch operations, async queries, retry policies — # everything your driver supports works unchanged.
-- Self-hosted observability via CQL virtual tables SELECT * FROM system_observability.cql_stats; SELECT * FROM system_observability.slow_queries; SELECT * FROM system_observability.query_fingerprints; -- Find queries causing full table scans SELECT * FROM system_observability.full_scan_reasons; -- Per-client billing metering SELECT * FROM system_observability.client_usage; -- Distributed traces (self-hosted, no Jaeger needed) SELECT * FROM system_observability.spans WHERE trace_id = ?; -- Prometheus metrics at /metrics, CLI: ferrosa-ctl monitor (TUI) -- WebSocket push: ws://host:9090/api/ws (subscribe/unsubscribe)
How We Compare
Search, vectors, graph, SPARQL, transactions, CDC. One database. AI native.
| Ferrosa | Cassandra | ScyllaDB | DynamoDB | Keyspaces | |
|---|---|---|---|---|---|
| Language | Rust | Java | C++ | Proprietary | Managed |
| GC Pauses | None | Yes (JVM) | None | N/A | N/A |
| Memory Safety | Guaranteed | GC-managed | Manual (C++) | N/A | N/A |
| CQL Compatible | ✓ v4/v5 | ✓ | ✓ | ✗ | Partial |
| S3-Native Storage | ✓ | ✗ | ✗ | ✗ | ✗ |
| Graph Queries | ✓ Cypher + Bolt | ✗ | ✗ | ✗ | ✗ |
| Vector Search | ✓ HNSW + IVFFlat | SAI (limited) | ✗ | ✗ | ✗ |
| Full-Text Search | ✓ BM25 + analyzers | SASI (deprecated) | ✗ | ✗ | ✗ |
| NVMe Table Pinning | ✓ per-table | ✗ | ✗ | DAX (cache) | ✗ |
| Secondary Indexes | 11 types (incl. FTS) | SAI / 2i | SI | GSI / LSI | GSI |
| Real-Time Pub/Sub | ✓ SUBSCRIBE | CDC (external) | CDC (external) | DynamoDB Streams | ✗ |
| UDF Language | ✓ WASM | Java | Lua / WASM | N/A | N/A |
| Built-in Observability | ✓ CQL + TUI + Web + WS | JMX/nodetool | Prometheus | CloudWatch | CloudWatch |
| Production Ops | Hinted handoff, auto-reconnect, graceful drain, token rebalance, systemd | Manual (nodetool) | Manual + Operator | Managed | Managed |
| Transactions | ✓ Accord (strict serializable) | LWT (Paxos) | LWT (Paxos) | ACID (single-table) | LWT (Paxos) |
| Consensus | Raft + Accord | Paxos (Accord in 5.x) | Paxos (Pegasus) | N/A (managed) | N/A (managed) |
| Node Recovery | Seconds | Hours | Hours | Automatic | Automatic |
| Storage Cost (PB) | ~$23K/mo (tiered: ~$8K) | ~$100–250K/mo | ~$100–250K/mo | ~$250K/mo | ~$250K/mo |
| Recovery Cost (PB, 30d) | ~$2/mo (commit log only) | ~$150K/mo (EBS snapshots) | ~$150K/mo (EBS snapshots) | ~$250K/mo (on-demand) | ~$250K/mo (on-demand) |
| Recovery Cost (PB, 1yr) | ~$45/mo (Glacier tiered) | ~$500K+/mo | ~$500K+/mo | N/A (35 days max) | N/A (35 days max) |
| Vendor Lock-In | None | None | Cloud tier | Full (AWS) | Full (AWS) |
Under the Hood
Each layer is an independent, tested crate. Use the full stack or embed individual components.
Built For
Migration
Same CQL protocol, same drivers, same consistency model. Import existing SSTables directly. Migrate one keyspace at a time with dual-read verification. Your application never knows the difference.
Scale Seamlessly
Start with a single node on your laptop. Add a second node for high availability with automatic pair mode. Scale to 3+ nodes and Ferrosa forms a full production cluster with Raft consensus, tunable consistency levels, hinted handoff, and node lifecycle management. Same binary, same config format — just add nodes.
Graph + Relational
Stop running separate databases for each workload. Ferrosa speaks CQL for your transactional workloads and Cypher for graph traversals — same tables, same cluster, same operational surface.
Grow With You
Start on your laptop, ship to production. No re-architecture, no migration between tiers. The same Ferrosa binary handles every stage of your growth.
1 Node
Run a single Ferrosa node locally. Full CQL compatibility, graph queries, and SUBSCRIBE all work out of the box. No cluster setup, no coordination overhead. Your application code stays exactly the same as you scale up.
2 Nodes
Add a second node and Ferrosa automatically enters pair mode — synchronous replication with instant failover. All 11 DDL operations replicate automatically: CREATE, ALTER, and DROP for keyspaces, tables, and roles, plus GRANT and REVOKE. Schema catch-up on rejoin, operator switchover, and force-promote for split-brain recovery.
3+ Nodes
Add a third node and Ferrosa transitions to full cluster mode: Raft consensus for metadata (openraft), Murmur3 token ring for data sharding, and a coordinator pattern with tunable consistency levels (ONE, QUORUM, ALL, LOCAL_QUORUM, EACH_QUORUM). Hinted handoff stores writes for temporarily failed replicas and replays on recovery. Streaming protocol handles node bootstrap and decommission. Skew-aware token rebalancing keeps load evenly distributed. Deploy with Docker Compose or bare metal.
Download
Ferrosa is under active development. Sign up below to be notified when the first release is available.
See the getting started guide for architecture and design details.
Install, configure, and connect your first CQL driver in minutes.
Step-by-step walkthroughs for IoT, analytics, e-commerce, and 10 more use cases — with runnable CQL scripts.
Full CQL reference with supported statements, types, and functions.
CQL, Cypher, SPARQL, and vector search — one database for all your workloads.
Ferrosa is in active development. Binary releases are coming soon.