← Back to homepage

Migration Guide

Move from Apache Cassandra to Ferrosa without rewriting application code. Same CQL protocol, same drivers, same consistency model.

Beta: Ferrosa is currently in beta. We recommend thorough testing with representative workloads before migrating production traffic.

On this page

Migration Overview

Ferrosa is designed as a drop-in replacement for Apache Cassandra at the protocol level. The migration strategy is incremental:

  1. Start a Ferrosa node alongside your existing Cassandra cluster
  2. Point a test workload at Ferrosa to validate compatibility
  3. Import existing SSTables directly (Ferrosa reads Cassandra BTI format)
  4. Migrate production keyspaces one at a time with dual-read verification
  5. Decommission Cassandra nodes as Ferrosa proves stable
Zero driver changes: Ferrosa speaks CQL protocol v5 with SASL authentication, LZ4/Snappy compression, and prepared statement support. Your Python, Java, Go, and Node.js drivers connect without modification.

What's Compatible

FeatureStatusNotes
CQL protocol v5CompatibleAll 16 opcodes
SASL authenticationCompatiblePasswordAuthenticator flow
Frame compressionCompatibleLZ4, Snappy
Prepared statementsCompatibleW-TinyLFU cache
Batch operationsCompatibleUnlogged batches
system_schema.*CompatibleAll standard tables
system.localCompatibleIncluding tokens column
Murmur3PartitionerCompatibleSame token distribution
BTI SSTablesCompatibleRead Cassandra 5.x SSTables directly
Consistency levelsCompatibleONE, TWO, THREE, QUORUM, ALL, LOCAL_ONE, LOCAL_QUORUM, EACH_QUORUM
cqlshCompatibleTested with Cassandra cqlsh
Hinted handoffCompatibleStores hints for down nodes, replays on recovery
Node lifecycleCompatibleJoin and decommission via ferrosa-ctl
Token rebalancingCompatibleOperator-triggered via ferrosa-ctl rebalance
Secondary indexesCompatible8 index types including vector (HNSW, IVFFlat)
UDTsSupportedCREATE/ALTER/DROP TYPE fully implemented
Materialized viewsNot yetPlanned
LWTNot yetPlanned
Gossip protocolReplacedFerrosa uses Raft for metadata (not wire-compatible)
Internode protocolReplacedCustom binary protocol (not wire-compatible)
Important: Ferrosa is client-compatible (CQL drivers work unchanged) but not cluster-compatible (a Ferrosa node cannot join an existing Cassandra ring). Migration is done by importing data, not by mixed-version rolling upgrades.

Step-by-Step Migration

1

Audit your schema

Export your Cassandra schema and check for unsupported features. Ferrosa supports all standard CQL types, partition/clustering keys, table options, and UDTs. Check for materialized views or UDFs — these are not yet supported.

# Export schema from Cassandra
cqlsh -e "DESCRIBE SCHEMA" > schema.cql

# Check for unsupported features
grep -i "MATERIALIZED VIEW\|CREATE FUNCTION" schema.cql
2

Start a Ferrosa node

Run Ferrosa alongside your existing cluster. It doesn't need to join the Cassandra ring.

# Build and start
cargo build --release
FERROSA_CQL_BIND=0.0.0.0:9042 \
FERROSA_AUTH_DISABLED=true \
./target/release/ferrosa
3

Apply your schema

Run your exported schema against Ferrosa. Remove any unsupported objects first.

# Apply schema to Ferrosa
cqlsh ferrosa-host 9042 -f schema.cql
4

Import data

Two options: SSTable import (fastest for large datasets) or CQL COPY/INSERT (simpler for smaller datasets).

# Option A: CQL COPY (simple, works for moderate datasets)
# Export from Cassandra
cqlsh cassandra-host -e "COPY social.users TO '/tmp/users.csv'"

# Import to Ferrosa
cqlsh ferrosa-host -e "COPY social.users FROM '/tmp/users.csv'"

# Option B: SSTable import (see SSTable Import section below)
5

Validate with dual reads

Run your application against both Cassandra and Ferrosa, comparing results. See the dual-read verification section below.

6

Cut over

Once validation passes, update your driver contact points from Cassandra to Ferrosa.

# Your application code — just change the host
# Before:
# cluster = Cluster(['cassandra-node-1.prod'])

# After:
cluster = Cluster(['ferrosa-node-1.prod'])

SSTable Import

Ferrosa's ferrosa-sstable crate reads Cassandra BTI (Big Trie-Indexed) SSTables natively — the default format in Cassandra 5.x. This means you can import existing SSTable files directly without an intermediate conversion step.

What Ferrosa reads

A BTI SSTable consists of 7 component files:

Copy these files from your Cassandra data directory to Ferrosa's data directory, organized by keyspace and table. Ferrosa will pick them up on next read.

Note: SSTable import is currently a manual file-copy process. A dedicated ferrosa-import CLI tool with validation and progress reporting is planned for a future release.

Compression support

Ferrosa supports LZ4 and Zstd compressed SSTables. No decompression step needed — compressed SSTables are read directly.

Big format (pre-5.x): If you're running Cassandra 4.x or earlier with the Big SSTable format, you'll need to upgrade to Cassandra 5.x first (which converts to BTI), or use nodetool upgradesstables to force conversion. Big format read support is planned for a future Ferrosa release.

Dual-Read Verification

Before cutting over production traffic, run dual reads against both databases and compare results:

from cassandra.cluster import Cluster

# Connect to both
cass = Cluster(['cassandra-host']).connect('social')
ferro = Cluster(['ferrosa-host']).connect('social')

# Compare results
query = "SELECT * FROM users WHERE user_id = ?"
stmt_c = cass.prepare(query)
stmt_f = ferro.prepare(query)

for uid in sample_user_ids:
    row_c = cass.execute(stmt_c, [uid]).one()
    row_f = ferro.execute(stmt_f, [uid]).one()
    assert row_c == row_f, f"Mismatch for {uid}"

Run this against a representative sample of your production queries. Cover:

S3 Storage Setup

For production, configure S3 as the durable storage backend. Local disk acts as a hot cache.

# AWS S3 with IAM instance profile (no explicit keys needed)
FERROSA_S3_ENDPOINT=https://s3.amazonaws.com \
FERROSA_S3_BUCKET=my-ferrosa-data \
FERROSA_S3_REGION=us-east-1 \
FERROSA_DATA_DIR=/var/lib/ferrosa \
./target/release/ferrosa

# MinIO for local development
FERROSA_S3_ENDPOINT=http://localhost:9000 \
FERROSA_S3_BUCKET=ferrosa \
FERROSA_S3_ACCESS_KEY_ID=minioadmin \
FERROSA_S3_SECRET_ACCESS_KEY=minioadmin \
FERROSA_S3_ALLOW_HTTP=true \
./target/release/ferrosa

S3-compatible providers

Ferrosa works with any S3-compatible object store. Set FERROSA_S3_ENDPOINT for non-AWS providers:

ProviderEndpoint
AWS S3(default — no endpoint needed)
MinIOhttp://minio:9000
Cloudflare R2https://<account>.r2.cloudflarestorage.com
DigitalOcean Spaceshttps://<region>.digitaloceanspaces.com
Backblaze B2https://s3.<region>.backblazeb2.com

Storage cost comparison

With S3-backed storage, you trade local disk costs for object storage costs — typically a 4-10x reduction:

ScaleEBS (gp3, 3 replicas)S3 StandardSavings
1 TB~$240/mo~$23/mo~10x
10 TB~$2,400/mo~$230/mo~10x
100 TB~$24,000/mo~$2,300/mo~10x
1 PB~$240,000/mo~$23,000/mo~10x

S3 request costs (GET/PUT) add overhead for high-throughput workloads, but the local NVMe cache absorbs most read traffic. Write-behind uploads batch SSTables to amortize PUT costs.

Key Differences from Cassandra

AreaCassandraFerrosa
Cluster membership Gossip protocol Raft (openraft) for metadata consensus
Internode protocol Cassandra messaging Custom binary protocol with 3 priority lanes, PSK auth
Storage durability Local disk (EBS/SSD) S3 (local NVMe as cache)
Node recovery Stream from replicas (hours) Read from S3 (seconds)
GC pauses JVM stop-the-world None (Rust, no GC)
Observability JMX + nodetool CQL virtual tables + Prometheus + TUI + Web console
Real-time pub/sub CDC (requires Kafka/Debezium) Built-in SUBSCRIBE with EVERY/DELTA modes
Graph queries Not supported Cypher via HTTP/JSON on the same tables
SSTable format Big + BTI Reads BTI, writes BTI (native format planned)
Commit log Standard CAS-allocated segments, 3 sync modes, built-in CDC

Rollback Plan

If you need to roll back to Cassandra:

  1. Keep Cassandra running during the migration period — don't decommission until you're confident
  2. Your application code is unchanged — rolling back is just changing the contact point back to Cassandra
  3. Export data from Ferrosa using cqlsh COPY if you need to sync writes that went only to Ferrosa
  4. No schema changes needed — your schema is the same on both systems
Low risk: Because Ferrosa uses the same CQL protocol and the same drivers, rollback is a configuration change, not a code change. Keep both systems running during validation and cut over only when you're confident.