Skip to main content
Swytch Documentation
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

Migrating from Redis

Swytch’s Redis mode is 100% command-compatible with Redis. Same wire protocol (RESPv2 and RESPv3), same commands, same ACL format, same client libraries. Migrating doesn’t mean rewriting your application; it means moving traffic safely. This page is the playbook for that: shadow testing, dual-write, cutover, and rollback, with Redis available as a fallback at every step until the day you decommission it.

Why migrate

Migrations are disruptive enough that “it’s newer” isn’t a reason. The reasons teams move a Redis workload to Swytch usually come down to three things:

  • Operations. There is no Sentinel to configure, no hash slots to rebalance, no failover runbooks to write. Every node is a peer, and cluster membership is a DNS name. Swytch vs Redis covers the architecture.
  • Cost. Swytch runs as a sidecar on the application servers you already operate, using RAM they already have. For most deployments, the dedicated cache tier disappears from the bill entirely. Economics of Swytch has the numbers.
  • Multi-region. Every node accepts writes, and adding a region is adding a node, so active-active is the default topology rather than an enterprise add-on. Swytch vs Redis (Enterprise) compares against the commercial product.

There is a correctness upgrade too: MULTI/EXEC in Swytch is a serializable transaction, so the WATCH-and-retry loops Redis requires for atomicity become optional.

If none of that applies to your workload, staying on Redis is a reasonable choice, and the comparison pages linked above are explicit about where Redis remains the better fit. If it does apply, the rest of this page is the migration.

Migration overview

PhaseDurationRisk levelRollback
PreparationDays-weeksNoneN/A
Shadow testingDaysLowInstant
Dual-writeHours-daysLowInstant
CutoverMinutesMediumMinutes
ValidationHours-daysLowMinutes
CleanupDaysNoneN/A

Step 1: Verify command compatibility

Review your application’s Redis usage against supported commands. A few Redis features map to architectural differences rather than missing commands:

FeatureSwytchNotes
Client-side cluster modeNot neededSwytch uses its own leaderless clustering
Primary-replica replicationNot usedSwytch replicates synchronously to subscribers; cluster membership via --join
Multiple databases (SELECT)Single databaseSELECT 0 is accepted for compatibility; run a separate instance per database
Persistence (RDB/AOF)Different modelData lives in RAM across subscribed nodes; Swytch Cloud adds durable storage
Modules (RediSearch, RedisJSON)Not supportedNo module system yet
Lua cjson/cmsgpackNot supportedUse application-side serialization
ACLsSupportedUse --aclfile (Redis-compatible ACL format)
TLSSupportedNative TLS and mTLS via --tls-* flags

The first two rows aren’t missing features; they’re places where Redis’s single-primary model and Swytch’s leaderless model differ at the architecture level. Your application’s Redis client connects to Swytch the same way it connects to Redis; what happens behind the wire protocol is what’s different.

One behavior difference deserves a specific code audit: commands inside MULTI return their actual values, not QUEUED placeholders. Code that parses for QUEUED needs to adjust. Code that ever wanted intermediate values inside an atomic block gets them for free, which removes most reasons to reach for Lua.

Step 2: Set up a shadow instance

Deploy Swytch as a sidecar next to your application, using a different port from your existing Redis:

# Sidecar deployment on the same host as the app
swytch redis --port 6380 --maxmemory 4gb --metrics-port 9090

The application will connect to both Redis and Swytch over localhost during the shadow and dual-write phases. This is also the deployment shape you keep after the migration: the app talks to its local node, and the network hop moves to replication between nodes instead of sitting between your app and its cache.

Step 3: Implement dual-write

Modify your application to write to both Redis and Swytch:

import redis

class DualWriteClient:
    def __init__(self, primary_host, shadow_host):
        self.primary = redis.Redis(host=primary_host, port=6379)
        self.shadow = redis.Redis(host=shadow_host, port=6380)
        self.shadow_enabled = True

    def set(self, key, value, **kwargs):
        # Always write to primary
        result = self.primary.set(key, value, **kwargs)

        # Shadow write (fire-and-forget, don't block on errors)
        if self.shadow_enabled:
            try:
                self.shadow.set(key, value, **kwargs)
            except Exception as e:
                # Log but don't fail the request
                logger.warning(f"Shadow write failed: {e}")

        return result

    def get(self, key):
        # Read from primary only during shadow phase
        return self.primary.get(key)

Step 4: Shadow read validation

After the cache warms up, add shadow reads to compare results:

def get_with_validation(self, key):
    primary_result = self.primary.get(key)

    if self.shadow_enabled:
        try:
            shadow_result = self.shadow.get(key)
            if primary_result != shadow_result:
                logger.error(f"Mismatch for {key}: primary={primary_result}, shadow={shadow_result}")
                metrics.increment("shadow_mismatch")
            else:
                metrics.increment("shadow_match")
        except Exception as e:
            logger.warning(f"Shadow read failed: {e}")

    return primary_result

Run this for at least one full cache TTL cycle to validate consistency.

Step 5: Cutover

Once validation passes:

  1. Update connection strings to point to Swytch.
  2. Keep Redis running as fallback.
  3. Monitor closely for the first hour.
# Feature flag cutover
if feature_flags.get("use_swytch"):
    cache = redis.Redis(host="swytch-host", port=6379)
else:
    cache = redis.Redis(host="redis-host", port=6379)

Step 6: Rollback plan

If issues arise:

  1. Immediate. Flip a feature flag back to Redis.
  2. Data sync. If Swytch had writes Redis doesn’t have, replay from application logs or accept data loss for cache.
  3. Post-mortem. Analyze what went wrong before retrying.

Step 7: Cleanup

After running successfully for 1–2 weeks:

  1. Remove dual-write code.
  2. Decommission the old Redis instances, along with the Sentinel processes or Cluster tooling that managed them.
  3. Update monitoring and runbooks. The failover runbooks come out entirely; there is no failover to run.

Data migration

Option 1: Online migration with RIOT

RIOT can replicate data between Redis instances. Since Swytch doesn’t respond to Redis replication commands, use RIOT’s scan mode:

riot-redis -u redis://old-redis:6379 replicate -u redis://swytch:6380 --mode scan

Option 2: Application-driven migration

For cache workloads, the simplest path is to let the application repopulate Swytch naturally:

  1. Deploy Swytch with an empty database.
  2. Point the application at Swytch.
  3. Cache misses hit the source of truth and populate Swytch.
  4. After one TTL cycle, the cache is fully warm.

This is often the safest approach for cache workloads, since there’s no data-transfer step that could fail mid-migration.

Validation checklist

Before declaring migration complete:

  • All application endpoints tested
  • Hit rate matches or exceeds the previous cache
  • Latency p50/p99 within acceptable range
  • No error rate increase
  • Memory usage stable
  • Metrics and alerts configured
  • Runbooks updated
  • On-call team briefed
  • Rollback tested and documented

Common migration issues

IssueCauseSolution
Higher miss rate after cutoverCache not warmedPre-warm, or accept temporary misses
Latency spikeCold cacheIncrease --maxmemory or wait for warm
Connection errorsClient timeout too aggressiveIncrease client timeout
Memory growing unexpectedlyDifferent overhead than RedisAdjust --maxmemory based on actual
Command not supportedUsing an unsupported Redis featureCheck compatibility, modify app