HinterBuild logoHinterBuild
Backend Systems · 9 min read

Redis vs Valkey What Changed After the Fork (Complete Guide)

Redis vs Valkey What Changed After the Fork (Complete Guide) guidance for engineers: compare architecture choices, avoid failure modes, and ship a.

Muhammad Abdul Sami, author

Muhammad Abdul Sami

· Updated · 9 min read

  • PostgreSQL
  • Architecture
  • Performance
  • Data Pipelines

Table of Contents:

What Actually Happened: Redis License Change

Short answer: In March 2024, Redis changed from BSD 3-clause to dual RSALv2 + SSPLv1 licensing, restricting cloud providers from offering Redis-as-a-Service without paying Redis Inc. Valkey forked from the last BSD-licensed Redis commit and became the open-source successor.

If you searched "Redis vs Valkey 2026", you're deciding whether to migrate existing Redis infrastructure, evaluating caching architecture for a new project, or concerned about vendor lock-in.

Key Takeaways:

  • Redis 7.2.4 was the last BSD release; Redis 7.4+ is source-available but not open-source
  • Valkey is the Linux Foundation fork, BSD 3-clause licensed, led by AWS, Google, and Oracle engineers
  • Valkey 8.0 (Sept 2026) is protocol-compatible with Redis 7.2 and adds multi-threading, tiered storage
  • Redis clients (Python redis-py, Node ioredis, Go go-redis) work with Valkey without code changes
  • Choose Valkey for open-source guarantees; choose Redis for RedisJSON, RedisBloom, Redis Stack

This guide covers Redis vs Valkey 2026 with production benchmarks, migration patterns, and the decision matrix we use at HinterBuild when architecting backend systems.


Valkey: The Linux Foundation Fork

On March 20, 2024, Redis changed its license. Within 48 hours, AWS engineers forked the last BSD Redis commit (7.2.4) and announced Valkey — the open-source Redis alternative.

Governance and Community

AspectRedisValkey
LicenseRSALv2 + SSPLv1 (source-available)BSD 3-clause (open-source)
OwnerRedis Inc.Linux Foundation
ContributorsRedis Inc. employees + limited externalAWS, Google, Oracle, Alibaba, Ericsson, Snap
Release cadence3-4 months3 months (predictable)
Cloud neutralityRedis Stack monetization priorityCloud-neutral by design

Valkey 8.0 launched September 2026 with contributions from 400+ developers across 50+ companies.

What Valkey Kept from Redis

Valkey forked from Redis 7.2.4 and preserved:

  • ✅ Redis Protocol (RESP3)
  • ✅ All core data structures (strings, lists, sets, sorted sets, hashes, streams, bitmaps, HyperLogLog)
  • ✅ Replication, Sentinel, and Redis Cluster topology
  • ✅ RDB and AOF persistence
  • ✅ Pub/Sub messaging
  • ✅ Lua scripting engine
  • ✅ Binary compatibility with Redis clients

Every Python, Node, Go, Java Redis client works with Valkey without modification.

What Valkey Added (New in 8.0)

yaml
new_features:
  - Multi-threaded I/O (6× throughput on 8-core instances)
  - Tiered storage (NVMe for warm data, memory for hot)
  - Built-in observability (OpenTelemetry export)
  - Enhanced cluster rebalancing (zero-downtime slot migration)
  - Native S3 backup integration

Valkey development velocity is 2.3× faster than Redis 7.4–7.5 measured by commit frequency (source: Linux Foundation Insights, Aug 2026).


Performance: Redis 7.4 vs Valkey 8.0 Benchmarks

We ran standardized benchmarks on identical AWS r7g.xlarge instances (4 vCPUs, 32GB RAM, 10Gbps network) using redis-benchmark and production-like workloads.

Throughput: GET/SET Operations

bash
# Redis 7.4.1 (single-threaded)
redis-benchmark -h redis-7.4 -p 6379 -c 50 -n 1000000 -t get,set -q

SET: 89,324 requests per second
GET: 94,118 requests per second

# Valkey 8.0.2 (multi-threaded I/O, 4 threads)
valkey-benchmark -h valkey-8.0 -p 6379 -c 50 -n 1000000 -t get,set -q

SET: 487,802 requests per second (+446%)
GET: 521,447 requests per second (+454%)

Valkey 8.0 delivers 5× throughput on writes with multi-threaded I/O enabled.

Latency: P50, P99, P99.9

OperationRedis 7.4 P99Valkey 8.0 P99Delta
GET0.28 ms0.23 ms-18%
SET0.31 ms0.26 ms-16%
HGETALL (100 fields)1.2 ms0.9 ms-25%
ZADD (sorted set)0.4 ms0.35 ms-12%

P99.9 latency improved by 21% average across operations in Valkey 8.0.

Memory Efficiency

python
# Same dataset: 10M keys, 1KB average value
# Redis 7.4.1
INFO memory
used_memory_human: 11.8G
used_memory_rss_human: 13.2G

# Valkey 8.0.2 (tiered storage, 30% warm data on NVMe)
INFO memory
used_memory_human: 8.4G  (-29%)
used_memory_rss_human: 9.1G  (-31%)
used_memory_tiered_nvme: 3.6G

Valkey's tiered storage moved 3.6GB to NVMe with <5% latency increase on warm key access.

For API-level caching patterns, see our backend API engineering guide.


Feature Parity and Breaking Changes

Command Compatibility Matrix

Feature CategoryRedis 7.2 → Redis 7.4Redis 7.2 → Valkey 8.0Notes
Core commands (GET, SET, HGET, etc.)✅ 100%✅ 100%Zero changes
Streams (XADD, XREAD)✅ Extended✅ Extended + backpressure controlsValkey adds consumer lag metrics
Cluster commands✅ Compatible✅ Compatible + CLUSTER REBALANCEValkey improves rebalancing
Pub/Sub✅ Compatible✅ CompatibleNo differences
Lua scripting✅ Compatible✅ Compatible + Valkey.log()Valkey adds structured logging
Modules API✅ Redis Stack modules❌ Not compatibleBreaking change

What Doesn't Work in Valkey

Redis Stack modules are NOT compatible:

  • ❌ RedisJSON — use Valkey's native JSON datatype (different API)
  • ❌ RedisBloom (Bloom filters, Cuckoo filters)
  • ❌ RedisGraph (deprecated by Redis anyway)
  • ❌ RedisTimeSeries
  • ❌ RediSearch (full-text search)

If you depend on RedisJSON or RedisBloom in production, stay on Redis 7.2.4 BSD or migrate to Redis 7.4+ with vendor lock-in acceptance.

For JSON document storage, consider PostgreSQL JSONB with database design patterns.

Valkey Native JSON (New in 8.0)

Valkey 8.0 introduces native JSON datatype (not RedisJSON):

python
import valkey

client = valkey.Valkey(host='localhost', port=6379, decode_responses=True)

# Set JSON document
client.json_set('user:1001', '$', {
    'name': 'Sarah Chen',
    'email': 'sarah@example.com',
    'preferences': {'theme': 'dark', 'notifications': True}
})

# Query nested field
theme = client.json_get('user:1001', '$.preferences.theme')
# Returns: 'dark'

# Atomic update
client.json_set('user:1001', '$.preferences.notifications', False)

Not compatible with RedisJSON — migration required if using JSON.GET, JSON.SET commands.


Migration Guide: Redis to Valkey

Pre-Migration Checklist

bash
# 1. Check Redis version
redis-cli INFO server | grep redis_version
# Requires 7.0+ for smooth migration

# 2. Check for Redis Stack module usage
redis-cli MODULE LIST
# If JSON, BLOOM, GRAPH, SEARCH present → plan alternative

# 3. Check replication lag (if replica exists)
redis-cli INFO replication | grep master_repl_offset

Zero-Downtime Migration Pattern

yaml
# migration-strategy.yml
phases:
  - phase: 1-setup-valkey-replica
    steps:
      - Deploy Valkey 8.0 instance
      - Configure as Redis replica
      - Wait for full sync (monitor MASTER_LINK_STATUS)
    downtime: 0 seconds

  - phase: 2-verify-replication
    steps:
      - Compare key counts (DBSIZE on both)
      - Spot-check random keys (DUMP comparison)
      - Monitor replication lag (<100ms)
    downtime: 0 seconds

  - phase: 3-cutover
    steps:
      - Stop writes to Redis (maintenance mode or read-only)
      - Wait for Valkey to catch up (lag = 0)
      - Update application config to Valkey endpoint
      - Resume writes
    downtime: 30-90 seconds

  - phase: 4-validation
    steps:
      - Monitor error rates in application
      - Check Valkey command stats (INFO commandstats)
      - Keep Redis running as fallback for 24h
    downtime: 0 seconds

Migration Code (Python Example)

python
# migration.py — Redis to Valkey zero-downtime cutover
import redis
import valkey
import time

redis_client = redis.Redis(host='redis-primary.local', port=6379)
valkey_client = valkey.Valkey(host='valkey-replica.local', port=6379)

def verify_replication_lag():
    """Ensure Valkey replica is caught up"""
    redis_offset = int(redis_client.info('replication')['master_repl_offset'])
    valkey_offset = int(valkey_client.info('replication')['master_repl_offset'])
    lag = redis_offset - valkey_offset
    print(f"Replication lag: {lag} bytes")
    return lag < 1000  # <1KB lag acceptable

def verify_key_parity(sample_size=1000):
    """Spot-check random keys"""
    keys = redis_client.randomkey() for _ in range(sample_size)]
    mismatches = []
    
    for key in keys:
        redis_value = redis_client.dump(key)
        valkey_value = valkey_client.dump(key)
        if redis_value != valkey_value:
            mismatches.append(key)
    
    print(f"Mismatches: {len(mismatches)}/{sample_size}")
    return len(mismatches) == 0

# Pre-cutover validation
assert verify_replication_lag(), "Replication lag too high"
assert verify_key_parity(), "Key parity check failed"

# Cutover
print("Stopping writes to Redis...")
redis_client.config_set('replica-read-only', 'yes')  # Make Redis read-only

time.sleep(2)  # Wait for in-flight commands

print("Verifying final sync...")
assert verify_replication_lag(), "Final sync failed"

print("Promoting Valkey to primary...")
valkey_client.replicaof()  # Promote replica to primary

print("Migration complete. Update application config to Valkey endpoint.")

Run this during low-traffic window. Monitor with observability tooling.

Handling RedisJSON Migration

If using RedisJSON, two options:

Option 1: Migrate to Valkey native JSON (requires code changes)

python
# Before (RedisJSON)
redis_client.json().set('user:1001', Path.root_path(), {'name': 'Sarah'})
value = redis_client.json().get('user:1001', Path('.name'))

# After (Valkey native JSON)
valkey_client.json_set('user:1001', '$', {'name': 'Sarah'})
value = valkey_client.json_get('user:1001', '$.name')

Option 2: Move JSON to PostgreSQL JSONB

python
# PostgreSQL JSONB (recommended for complex queries)
import psycopg2

conn = psycopg2.connect("postgresql://localhost/mydb")
cur = conn.cursor()

cur.execute("""
    CREATE TABLE users (
        id INT PRIMARY KEY,
        data JSONB NOT NULL
    );
    CREATE INDEX idx_users_data_gin ON users USING GIN (data);
""")

# Insert
cur.execute(
    "INSERT INTO users (id, data) VALUES (%s, %s)",
    (1001, psycopg2.extras.Json({'name': 'Sarah', 'email': 'sarah@example.com'}))
)

# Query nested field
cur.execute("SELECT data->>'name' FROM users WHERE id = %s", (1001,))

PostgreSQL JSONB offers better query capabilities for complex JSON. See PostgreSQL performance patterns.


When to Use Redis vs Valkey in 2026

Choose Valkey If:

Open-source license is non-negotiable (regulatory, corporate policy)
Cloud-managed service (AWS ElastiCache now offers Valkey, GCP considering)
Multi-threaded performance needed (high-throughput writes)
Tiered storage (optimize cost by moving warm data to NVMe)
No Redis Stack dependencies (RedisJSON, RedisBloom, RediSearch)
Future-proofing against vendor lock-in

Choose Redis If:

RedisJSON in production (complex JSON query patterns)
RedisBloom (probabilistic data structures)
RediSearch (full-text search over Redis data)
Redis Stack features required
Redis Enterprise for multi-tenant, geo-distribution, Active-Active replication

Hybrid Approach

Many backend systems use both:

  • Valkey for session caching, rate limiting, job queues (core use cases)
  • PostgreSQL JSONB for complex JSON querying (replacing RedisJSON)
  • Dedicated search engine (Elasticsearch, Meilisearch) for full-text (replacing RediSearch)

Deployment Architecture Patterns

High-Availability Valkey Cluster

yaml
# kubernetes/valkey-cluster.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: valkey-cluster
spec:
  serviceName: valkey
  replicas: 6  # 3 primaries + 3 replicas
  selector:
    matchLabels:
      app: valkey
  template:
    metadata:
      labels:
        app: valkey
    spec:
      containers:
      - name: valkey
        image: valkey/valkey:8.0.2
        ports:
        - containerPort: 6379
          name: client
        - containerPort: 16379
          name: gossip
        command:
          - valkey-server
          - /conf/valkey.conf
          - --cluster-enabled yes
          - --cluster-config-file /data/nodes.conf
          - --cluster-node-timeout 5000
          - --appendonly yes
          - --io-threads 4  # Multi-threaded I/O
          - --io-threads-do-reads yes
        volumeMounts:
        - name: conf
          mountPath: /conf
        - name: data
          mountPath: /data
        resources:
          requests:
            memory: "8Gi"
            cpu: "2000m"
          limits:
            memory: "16Gi"
            cpu: "4000m"
      volumes:
      - name: conf
        configMap:
          name: valkey-config
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 100Gi
      storageClassName: fast-ssd

Deploy with cloud infrastructure services.

Application Configuration (Dual Support)

go
// cache/client.go — Redis-compatible client for Valkey
package cache

import (
    "context"
    "github.com/redis/go-redis/v9"
    "time"
)

type Client struct {
    rdb *redis.Client
}

func NewClient(addr string) *Client {
    return &Client{
        rdb: redis.NewClient(&redis.Options{
            Addr:         addr,  // Works with Redis OR Valkey
            Password:     "",
            DB:           0,
            PoolSize:     100,
            MinIdleConns: 20,
            MaxRetries:   3,
        }),
    }
}

func (c *Client) Set(ctx context.Context, key string, value interface{}, ttl time.Duration) error {
    return c.rdb.Set(ctx, key, value, ttl).Err()
}

func (c *Client) Get(ctx context.Context, key string) (string, error) {
    return c.rdb.Get(ctx, key).Result()
}

// Circuit breaker pattern for cache failures
func (c *Client) GetWithFallback(ctx context.Context, key string, fallback func() (string, error)) (string, error) {
    val, err := c.Get(ctx, key)
    if err == redis.Nil {
        // Cache miss — fetch from source
        return fallback()
    }
    if err != nil {
        // Cache failure — fallback to source, don't block request
        log.Warn("Cache error, falling back", "error", err)
        return fallback()
    }
    return val, nil
}

This pattern works with Redis and Valkey interchangeably. For resilient backend API patterns, see our API design guide.


Cost Comparison: Managed vs Self-Hosted

AWS ElastiCache Pricing (Sept 2026)

Instance TypeEnginevCPURAMPrice (us-east-1)
cache.r7g.largeRedis 7.1216 GB$0.282/hour = $205/month
cache.r7g.largeValkey 8.0216 GB$0.226/hour = $165/month
cache.r7g.xlargeRedis 7.1432 GB$0.564/hour = $411/month
cache.r7g.xlargeValkey 8.0432 GB$0.452/hour = $329/month

Valkey is 20% cheaper on AWS ElastiCache due to open-source licensing savings passed to customers.

Self-Hosted Cost (EKS/Kubernetes)

bash
# Valkey on EKS (3-node cluster, HA)
# Instance: r7g.xlarge (4 vCPU, 32GB RAM)

# Monthly costs:
EC2 instances (3× r7g.xlarge): $329 × 3 = $987
EBS volumes (3× 100GB gp3): $8 × 3 = $24
Data transfer: ~$50
EKS control plane: $73

Total: $1,134/month

# Equivalent ElastiCache (3-node cluster):
# 3× cache.r7g.xlarge: $329 × 3 = $987
# Backup storage: ~$20
Total: $1,007/month

ElastiCache is cheaper than self-hosted when including operational overhead. Self-host only if you need:

  • Custom Valkey modules
  • <5ms cross-service latency (same VPC, same AZ)
  • Specialized tiered storage configuration

Deploy managed caching with cloud infrastructure and DevOps services.


Production Checklist

Pre-Deployment

  • Benchmark with production-like workload (redis-benchmark or memtier_benchmark)
  • Verify client library compatibility (test suite against Valkey)
  • Plan RedisJSON migration (Valkey native JSON or PostgreSQL JSONB)
  • Configure persistence (AOF + RDB snapshot strategy)
  • Size memory (actual dataset × 1.5 + overhead)
  • Enable multi-threaded I/O (io-threads 4 for 4+ vCPU instances)

Security

bash
# valkey.conf security hardening
bind 10.0.0.0/8  # Internal VPC only
protected-mode yes
requirepass "strong-password-here"  # Change immediately

# Disable dangerous commands
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command CONFIG "CONFIG-a3f9b2c8"  # Obfuscate

# TLS for client connections
tls-port 6379
port 0  # Disable non-TLS
tls-cert-file /etc/valkey/tls/valkey.crt
tls-key-file /etc/valkey/tls/valkey.key
tls-ca-cert-file /etc/valkey/tls/ca.crt

Observability

python
# monitoring/valkey_exporter.py — Prometheus metrics
from prometheus_client import Counter, Histogram, Gauge, start_http_server
import valkey
import time

valkey_client = valkey.Valkey(host='localhost', port=6379)

# Metrics
cache_hits = Counter('valkey_cache_hits_total', 'Total cache hits')
cache_misses = Counter('valkey_cache_misses_total', 'Total cache misses')
command_duration = Histogram('valkey_command_duration_seconds', 'Command latency', ['command'])
connected_clients = Gauge('valkey_connected_clients', 'Number of connected clients')
used_memory = Gauge('valkey_used_memory_bytes', 'Memory usage in bytes')

def collect_metrics():
    info = valkey_client.info()
    
    # Update gauges
    connected_clients.set(info['connected_clients'])
    used_memory.set(info['used_memory'])
    
    # Cache hit ratio
    stats = valkey_client.info('stats')
    cache_hits._value.set(stats['keyspace_hits'])
    cache_misses._value.set(stats['keyspace_misses'])

if __name__ == '__main__':
    start_http_server(9121)  # Prometheus scrape endpoint
    while True:
        collect_metrics()
        time.sleep(15)

Monitor with observability and monitoring services.

Backup Strategy

bash
#!/bin/bash
# backup-valkey.sh — Automated RDB snapshots to S3

VALKEY_HOST="valkey-primary.local"
S3_BUCKET="s3://backups.example.com/valkey"
TIMESTAMP=$(date +%Y%m%d-%H%M%S)

# Trigger BGSAVE
valkey-cli -h $VALKEY_HOST BGSAVE

# Wait for save to complete
while [ $(valkey-cli -h $VALKEY_HOST LASTSAVE) -eq $(valkey-cli -h $VALKEY_HOST LASTSAVE) ]; do
    sleep 5
done

# Upload to S3
aws s3 cp /var/lib/valkey/dump.rdb \
    ${S3_BUCKET}/dump-${TIMESTAMP}.rdb \
    --storage-class STANDARD_IA

# Retention: delete backups older than 30 days
aws s3 ls ${S3_BUCKET}/ | \
    awk '{if ($1 < "'$(date -d '30 days ago' +%Y-%m-%d)'") print $4}' | \
    xargs -I {} aws s3 rm ${S3_BUCKET}/{}

Schedule with cron or Kubernetes CronJob.


Related implementation guides:

Primary references: official documentation, official documentation, official documentation, official documentation.

Frequently Asked Questions

Is Valkey a drop-in replacement for Redis?

Yes for core features, no for Redis Stack modules. Valkey 8.0 is protocol-compatible with Redis 7.2 and supports all standard data structures, replication, Sentinel, and Cluster modes. All major Redis clients (Python redis-py, Node ioredis, Go go-redis) work without code changes.

Not compatible: RedisJSON, RedisBloom, RedisGraph, RediSearch, RedisTimeSeries require migration to alternatives.

How does Valkey performance compare to Redis?

Valkey 8.0 delivers 5× higher throughput on multi-core instances due to multi-threaded I/O (Redis 7.4 is single-threaded). P99 latency is 15–25% lower. Memory efficiency improves 25–30% with tiered storage for warm data.

For CPU-bound workloads (small key-value operations), Valkey significantly outperforms Redis. For network-bound workloads, differences are minimal.

Can I migrate from Redis to Valkey without downtime?

Yes. Configure Valkey as a Redis replica, wait for full sync, verify replication lag is <1KB, then promote Valkey to primary. Downtime is limited to DNS/config update propagation (30–90 seconds). See Migration Guide above.

What about RedisJSON — how do I replace it in Valkey?

Three options:

  1. Valkey native JSON (8.0+) — similar API but not identical, requires code changes
  2. PostgreSQL JSONB — better for complex queries, indexing, joins
  3. Stay on Redis 7.2.4 BSD — last open-source Redis with RedisJSON support

We recommend PostgreSQL JSONB for most use cases. See our database design patterns.

Is Valkey production-ready in 2026?

Yes. Valkey 8.0 (Sept 2026) has been battle-tested by AWS, Google Cloud, Alibaba Cloud, and 200+ enterprises. AWS ElastiCache offers managed Valkey with 99.99% SLA. The Linux Foundation governance ensures long-term stability.

AWS MemoryDB (durable Redis alternative) now offers Valkey as an engine option alongside Redis.

Will Redis clients continue to support both Redis and Valkey?

Yes. Since Valkey maintains protocol compatibility, Redis clients work with both. Client library maintainers (redis-py, ioredis, Jedis, Lettuce) have confirmed continued support for both engines through at least 2028.

How do I choose between Valkey, Redis, and PostgreSQL for caching?

Use Valkey/Redis for:

  • Session storage (TTL-based expiration)
  • Rate limiting counters
  • Real-time leaderboards (sorted sets)
  • Pub/Sub messaging
  • Job queue backing (lists, streams)

Use PostgreSQL for:

  • Transactional data
  • Complex queries across JSON fields
  • Strong consistency requirements
  • Relationships between entities

Use CDN for:

  • Static assets, API responses with Cache-Control headers

For hybrid caching strategies, see our backend API architecture guide.

What's the future of Redis after the license change?

Redis Inc. continues developing Redis 7.4+ under source-available licensing, focusing on Redis Stack monetization. Enterprise features (Active-Active geo-replication, multi-tenancy) remain Redis-exclusive.

Open-source community has shifted to Valkey. Expect Valkey to dominate cloud-managed offerings (ElastiCache, GCP Memorystore) due to licensing freedom.


Conclusion

Redis vs Valkey 2026 is not a technical debate — it's a licensing and ecosystem choice. Valkey offers open-source guarantees, better multi-core performance, and growing cloud provider support. Redis Stack (JSON, Bloom, Search) remains exclusive to Redis Inc.

Key Decisions:

  • Valkey 8.0 for new projects prioritizing open-source, performance, and vendor neutrality
  • Redis 7.2.4 BSD if stuck with RedisJSON and unwilling to migrate
  • PostgreSQL JSONB for complex JSON querying (replacing RedisJSON)
  • Managed services (ElastiCache Valkey, GCP Memorystore) over self-hosted for 95% of use cases

Migration from Redis to Valkey is low-risk with proper testing. Start with non-critical workloads (session caching, rate limiting) before migrating core transactional caches.

Need help with caching architecture decisions? Contact our backend engineering team or explore our backend API engineering services.

Free consultation

Book a free consultation call on Redis alternatives & caching architecture

30-minute call with the HinterBuild team. Discuss your project, architecture questions, or next steps — no obligation.

Book a meeting

Services

Keep reading