VeltrixDB vs. Redis
An honest comparison. Redis is excellent software with a massive ecosystem — VeltrixDB solves a different set of problems. Use this page to decide which one fits your workload.
The fundamental difference
Redis stores everything in RAM. It is fast by default and expensive at scale; with persistence on, fork-based snapshotting and AOF rewrites can cause latency spikes.
VeltrixDB stores values on NVMe SSDs behind a DRAM index and an LIRS cache. Every write is fdatasync-durable. It targets bounded P99 latency under sustained load, packs small values densely on disk (several records per 4 KB VLog block), and its VLog garbage collector escalates to an emergency mode that cannot be paused when garbage passes 65%. Redis has no comparable GC; its persistence-related tail spikes come from the fork behind RDB saves and AOF rewrites.
Latency at a glance
Measured VeltrixDB numbers, each with its conditions. There is no measured Redis run in the project; compare against your own Redis measurements rather than published figures.
| Measurement | VeltrixDB | Conditions |
|---|---|---|
| Cache-hit lookup, in-process | ~92 ns | Engine benchmark, sharded LIRS; no network |
| Read over the network, cache hit | avg 461 µs, P95 2.07 ms, P99 2.77 ms (427,697 ops/s) | YCSB 0.17.0 workload C, 200 threads, 100M keys all in a 400 GB cache, June 2026, pure-Go v1.0 |
| Durable write over the network | avg 11.06 ms, P95 30.8 ms, P99 47.3 ms (18,064 ops/s) | Same YCSB run, load phase, 5 ms fixed flush windows (before adaptive group commit), every write fdatasync'd |
| Durable single-key Put, adaptive group commit (default since v1.12) | 1 writer P50 0.45 ms (16 ms fixed); 64 writers 37.5K writes/s, P99 2.6 ms (4.0K fixed) | Engine test on macOS with an emulated 300 µs fdatasync, 15 ms window; not a Linux NVMe measurement |
| Batch writes (8 × 1024-key MPUT) | 1.77M keys/s, P99 12.2–12.7 ms | 4-CPU CI runner, tmpfs, client on same host · v1.7 |
| Reads over the network | 177–182K ops/s, P99 1.8–2.0 ms | Same CI runner · v1.7 |
NVMe cache-miss read latency has not been measured in a published run. The read path is one 4 KB-aligned Go pread per miss; P99 is kept bounded by the VLog GC throttling on read-latency EWMA (GC capped at 60 MB/s above 15 ms, paused above 20 ms), not by any I/O priority queue. An internal, unverified 3-node GKE run is described on Benchmarking Methodology.
Storage cost at scale
| Keys | Value size | Redis RAM (estimate) | VeltrixDB RAM (index) | VeltrixDB NVMe (packed values) |
|---|---|---|---|---|
| 100M | 128 B | ~25 GB | ~14–23 GB | ~15 GB |
| 1B | 128 B | ~250 GB | ~142–232 GB | ~160 GB |
| 100M | 1 KB | > 100 GB | ~14–23 GB | ~137 GB |
| 1B | 1 KB | > 1 TB | ~142–232 GB | ~1.4 TB |
Every cell is per-key arithmetic, not a measurement; 1 billion keys has not been measured reproducibly. The VeltrixDB RAM column is the index: about 142 B per key with the native index (measured at 5M keys), plus ~90 B per key for the ordered index unless --disable-ordered-index is set — plus whatever cache you configure. The RAM saving depends on value size. With 128-byte values the index is about as large as the values, so VeltrixDB saves little RAM; with 1 KB values it needs roughly 4–7× less. The NVMe column assumes packed writes (MultiPut, ~26 × 128 B records per 4 KB block); a single Put takes a whole 4 KB block. Price your own configuration rather than relying on a fixed RAM-to-NVMe ratio.
Write amplification
| Engine | Write amplification | Why |
|---|---|---|
| Redis (AOF rewrite) | periodic full rewrite | AOF rewrite rewrites the full dataset |
| RocksDB / LevelDB | commonly cited 10–30× | LSM compaction sorts and rewrites |
| VeltrixDB | ~1× by design for packed writes; not measured | Each value is appended once to the Value Log, and a small header + key record to the WAL. Values are rewritten only when VLog GC relocates live values out of a region that is mostly garbage (triggered at 30% dead space by default). A single small Put pads its record to a 4 KB block. |
Write amplification maps directly to SSD wear and write latency. Overwrite-heavy workloads pay for it through GC relocation; watch veltrixdb_vlog_garbage_ratio and veltrixdb_vlog_gc_runs_total (veltrixdb_vlog_gc_bytes_total counts bytes reclaimed, not bytes relocated).
When Redis wins
Use Redis when:
- Your full dataset fits comfortably in RAM — at, say, 5M keys and 256 bytes each, Redis’s DRAM-only path beats any disk-backed system at P50.
- You need pub/sub, streams, sorted sets, or Lua scripting — Redis has a rich data-structure model; VeltrixDB is a key-value store with hashes, lists, sets, counters, CAS, TTLs, ordered range scans, secondary indexes and multi-key transactions, but none of those four.
- Your team already runs Redis — operational familiarity has real value.
- You need a managed hosted service today — Redis Cloud, ElastiCache, and Upstash all exist. VeltrixDB’s managed offering is not yet available.
When VeltrixDB wins
Use VeltrixDB when:
- Your dataset doesn’t fit in RAM — or fitting it in RAM costs more than you want to pay. VeltrixDB’s LIRS cache keeps hot keys in DRAM; cold keys spill to NVMe automatically.
- You need predictable P99 under sustained write pressure — VeltrixDB’s GC throttles itself on read latency and escalates in tiers rather than stalling foreground traffic.
- You’re doing bulk writes at high concurrency —
MultiPutwith 1024-key batches measured 1.77M keys/s on a 4-CPU CI runner (tmpfs, client on the same host) and 3.54M keys/s on macOS, fdatasync-durable per batch (v1.7). - You’re running on Kubernetes with local NVMe — a Kubernetes Operator and a Helm chart (with an nvme-prep DaemonSet for GKE local SSDs) live in separate repositories; the main repository ships the
kubectl-veltrixplugin and Prometheus rules. - Write amplification matters — append-once values avoid LSM-style compaction rewrites; measure GC relocation for your overwrite rate.
Migrating from Redis
VeltrixDB does not speak RESP, so redis-cli and Redis client libraries cannot connect: migration means changing client code, not a connection string. The text protocol works with nc (served by the default --net=go front-end; the opt-in C++ front-end speaks only the binary protocol):
# Redis
redis-cli SET mykey myvalue
redis-cli GET mykey
# VeltrixDB (SET is accepted as an alias of PUT)
echo -e "PUT mykey myvalue\nGET mykey" | nc localhost 9000
| Redis | VeltrixDB |
|---|---|
SET / GET / DEL | PUT (alias SET) / GET / DEL |
SETEX, SET … EX | PUTEX key ttl-seconds value or the per-entry TTL of a binary MPUT (the binary PUT frame has no TTL field); no standalone EXPIRE / TTL for plain keys |
SETNX / INCR / DECR | SETNX, INCR key [delta], DECR key [delta], plus CAS key expected new |
MGET, pipelines | MGET; binary MPUT / MGET batches |
| Hashes, lists, sets | HSET (per-field TTL) HGET HDEL HGETALL HKEYS HLEN HEXPIRE HTTL; LPUSH RPUSH LPOP RPOP LRANGE LLEN; SADD SREM SMEMBERS SISMEMBER SCARD |
SCAN | SCANCUR / RANGE (ordered; local node only in a cluster) |
MULTI / EXEC / WATCH | TXN with SET / SETIF key version value / DEL: one-shot, optimistic, read-committed, not MVCC |
ZADD, PUBLISH, XADD, EVAL | no equivalent |
To copy data, veltrix-migrate import --dst host:9000 reads JSONL from stdin, one {"k": key, "v": base64 value} per line; there is no Redis importer, so produce that file yourself (for example with redis-py’s scan_iter + get). It sends one PUT at a time and does not carry TTLs.
For SDK migration, swap the client. The SDKs are maintained in a separate repository and this example was not verified against it; check the Python SDK page for the current API:
# Before (redis-py)
import redis
r = redis.Redis(host='localhost', port=6379)
r.set('key', 'value')
val = r.get('key')
# After (veltrixdb-python)
import veltrixdb
r = veltrixdb.Client(host='localhost', port=9000)
r.put('key', 'value')
val = r.get('key')
Vector and hybrid search vs. Redis Query Engine
Redis offers vector, full-text and hybrid queries through the Redis Query Engine (the RediSearch module in Redis Stack, bundled with Redis 8). VeltrixDB has them built in since v1.11. Feature level only — no performance comparison has been run.
| Capability | Redis Query Engine | VeltrixDB |
|---|---|---|
| Vector index / distance | HNSW and flat; cosine, L2, inner product | HNSW (k = 0 = exact scan); cosine only |
| Where vectors live | RAM, with the data | float32 persisted on NVMe; RAM holds float32, int8 or PQ codes, layer-0 graph optionally in a mapped file |
| Full-text | stemming, phrases, field weights | BM25 with a Unicode tokenizer; no stemming, phrases or field weights |
| Hybrid | KNN with a filter query | weighted reciprocal-rank fusion (HSEARCH) |
| Filters | tag / numeric / text fields | predicate on the KV record with the same id; = served by a secondary index |
| Restart | see Redis docs for your persistence setup | graph and inverted index rebuilt from durable keys; searches refused until done |
| Clients | every Redis client | Go client, or the text / binary protocol |
Commands, memory layouts, measured recall and RAM: Vector & Hybrid Search.
Feature matrix
| Feature | Redis | VeltrixDB |
|---|---|---|
| Data in RAM | all data | index + LIRS cache; values on NVMe |
| Predictable P99 under writes | spikes | bounded |
| NVMe storage tier | no | yes |
| Durable by default | no (needs appendfsync always) | yes (fdatasync per group commit) |
| Pub/Sub | yes | no |
| Sorted sets | yes | no (ordered key RANGE/SCANCUR only) |
| Lua scripting | yes | no |
| Hashes / lists / sets | yes | yes |
| Multi-key transactions | MULTI / EXEC | one-shot TXN (read-committed) |
| Secondary indexes | Query Engine module | yes (equality) |
| Vector / full-text / hybrid search | Query Engine module | built in (HNSW, BM25, RRF) |
| Kubernetes Operator | third-party | separate repository |
| Prometheus metrics | yes | yes |
| Encryption at rest | yes | yes (AES-256-GCM) |
| Multi-node replication | yes | Raft, or replicated (eventual default / quorum / strong) |
| Change data capture | no built-in | yes |
| Atomic CAS / INCR | yes | yes |
| SDKs (Go/Python/Node/Rust/C++) | yes | yes (Go in main repo; others in Veltrixdb-client) |
| RESP protocol | yes | roadmap |
| Managed cloud offering | yes | roadmap |
Benchmark reference
The only reproducible headline numbers are the single-node YCSB results (YCSB 0.17.0, June 9 2026, pure-Go v1.0 build, AWS EC2 high-memory instance with 495 GB RAM, 4× NVMe with raw block-device VLog, 400 GB LIRS cache, 200 client threads, 100M keys × ~100 B values):
Load (fdatasync-durable writes, 5 ms windows): 18,064 ops/s avg 11.06 ms P95 30.8 ms P99 47.3 ms 0 failures
Reads (workload C, whole dataset in cache): 427,697 ops/s avg 461 µs P95 2,069 µs P99 2,771 µs 100% hits
Later measurements with their conditions, the net-bench harness, and an internal (unverified) 3-node GKE run are on Benchmarking Methodology.
Questions?
Open an issue on GitHub or start a discussion. If you’re evaluating VeltrixDB for a production workload and want to talk through your specific requirements, the team is happy to help you benchmark against your actual data shape. See the FAQ for common questions.