DEV Community

장지호
장지호

Posted on

Why We Switched From Redis to Valkey (It Wasn't Just About the License)

When the migration first came up, everyone assumed it was purely a licensing decision. That part was real, but once we sat down to plan the actual cutover, the decisions that mattered most were somewhere else entirely: cross-AZ traffic costs, whether to turn cluster mode on, and a client library swap we hadn't fully budgeted for.

Valkey is a drop-in replacement for Redis OSS, maintained by the Linux Foundation under a BSD license. It keeps the Redis API compatible while removing the licensing constraints and fork uncertainty that started this whole conversation. Because our existing Redis clusters didn't need major rework to run on it, we could put together an incident response plan quickly instead of redesigning our caching layer from scratch.

Why we turned cluster mode off

The three key decisions in the Valkey migration: cluster mode, AZ costs, and the client library swap

The first call we had to make was whether to turn cluster mode on. Splitting data across multiple nodes for horizontal scaling sounds great on paper, but the further you shard, the messier resharding gets. We chose predictable latency and easier debugging over that risk, so cluster mode stayed off. Unless your traffic genuinely needs horizontal scale right now, running a single configuration with fewer failure points is the more realistic option.

Cross-AZ cost was the other half of that decision. Traffic between availability zones isn't free, and aligning the Redis layer within AZ boundaries cuts that cost. Scattering data across AZs with cluster mode on would have made the bill harder to reason about. Keeping it off and managing AZ placement directly kept the math simple.

From ioredis to node-redis: why the code had to change too

The migration plan also included swapping client libraries, from ioredis to node-redis. On paper it looks like a dependency bump, but it actually meant rewriting code and re-testing command compatibility. That's why we rolled it out to dev first before touching production. If something broke after a full library swap in prod, rolling back would have been painful, so we wanted to shrink the blast radius to dev before anything else.

Pinning exact versions mattered for the same reason. Recording something like Redis fork 7.2.4 instead of just "latest" meant we always had a clear rollback point the moment something went wrong. We made sure there was a way back at every step of the migration.

Why we waited for Valkey 9.0

There was one feature we'd been watching before the migration even started: hash field expiration, which shipped in Valkey 9.0. Previously, TTLs could only be set at the key level, which made things awkward whenever a hash mixed short-lived fields with ones meant to persist. According to Valkey's blog post on hash field expiration, you can now set a TTL per field, so different attributes of the same object can share a hash and still expire on their own schedule. That meant we could solve the problem without redesigning our cache structure.

Then AWS announced Valkey 9.0 support for Amazon ElastiCache, and the plan became something we could execute. Per the announcement, pipelined workloads can see throughput gains up to 40%, and the release also brought full-text search and multi-database support in cluster mode. The catch is that client connections can drop mid-upgrade. So before flipping anything on, we made sure dev/beta testing, retry/backoff logic, and monitoring around hash field expiration usage were all in place first. A new feature shipping doesn't mean turning it on immediately. It means checking first whether your system can tolerate the disruption.

The license is what started the migration, but the decisions that actually got it across the line were whether to enable cluster mode, how to cut AZ costs, and in what order to validate the client swap. Those three calls turned out to matter more than Valkey itself.

Thanks for reading.

Top comments (0)