Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes

Rename and copy keys

Learn how to rename and copy keys in Redis with clear steps and hands-on exercises. Understand the mental model, see when to use each command, and handle edge cases. Part of a progressive Redis tutorial series.

Focus: rename and copy keys

Sponsored

You've been carefully crafting Redis keys — session IDs, cached API responses, queue names — but then the requirements change. Maybe a service is deprecated and its key prefix needs updating, or you realize you've been using a confusing name. Deleting and recreating keys is risky and slow. Losing data because you typed DEL by mistake is a pain you don't need. Redis gives you the power to rename and copy keys in a single atomic command (or a safe script), letting you reorganize your key namespace without downtime or data loss.

The problem this lesson solves

Renaming or copying a key seems trivial — just read the value, write it to a new key, delete the old one. But in production, that sequence is dangerous:

  • Race conditions: A client writes to the old key between your read and write — your copy is stale.
  • Atomicity failure: If the delete step crashes, you now have duplicate or orphan keys.
  • Large values: For strings, sets, or hashes that hold megabytes of data, reading into memory and writing back is wasteful and slow.

Redis provides two commands that solve these problems: RENAME and COPY. Both operate server-side, atomically, and with minimal memory overhead.

Core concept / mental model

Think of a Redis key as a labeled box containing data. The label is the key name, the box is the data structure (string, list, set, etc.).

  • RENAME changes the label on the box. After rename, the old label no longer exists. If the new label already exists, its box is destroyed first — RENAME is an overwrite operation.
  • COPY creates a second label pointing to a new box with a duplicate of the original data. The original box stays untouched. COPY is available since Redis 6.2.

Key difference

Command Old key still exists? Overwrites destination? Atomic? Available since
RENAME No Yes (deletes old dest) Yes First versions
COPY Yes Optional (with REPLACE) Yes Redis 6.2

Pro tip: RENAME is always dangerous if you're not sure about the destination. If you need to keep the original key, use COPY.

How it works step by step

RENAME execution flow

  1. You send RENAME oldkey newkey.
  2. Redis checks if oldkey exists. If not, an error is returned.
  3. If newkey already exists, Redis atomically DELetes it.
  4. The value (and its TTL) from oldkey is moved to newkey.
  5. oldkey is removed from the keyspace.

COPY execution flow

  1. You send COPY source destination [DB destination-db] [REPLACE].
  2. Redis checks if source exists. If not, returns 0.
  3. If destination already exists: - Without REPLACE: command returns 0 (no copy). - With REPLACE: destination is DELeted first.
  4. The value from source is durably copied to destination. TTL is not preserved by default (the new key has no TTL unless you set it after).
  5. Returns 1 on success, 0 on failure.

Blockquote callout: COPY does not copy the TTL of the source key. If you need the same expiration, you must set it on the destination after the copy using EXPIRE.

Hands-on walkthrough

Let's work through real examples using redis-cli. We'll start with a string, then a hash, and finally a key with a TTL.

Example 1: Rename a simple string

redis-cli
127.0.0.1:6379> SET user:old:session abc123
OK
127.0.0.1:6379> RENAME user:old:session user:new:session
OK
127.0.0.1:6379> EXISTS user:old:session
(integer) 0
127.0.0.1:6379> GET user:new:session
"abc123"

The old key is gone; the new key holds the value.

Example 2: Copy a hash with REPLACE

127.0.0.1:6379> HSET config:prod host "db1.example.com" port 5432
(integer) 2
127.0.0.1:6379> HSET config:staging host "db2.example.com" port 5432
(integer) 2
127.0.0.1:6379> COPY config:prod config:staging REPLACE
(integer) 1
127.0.0.1:6379> HGETALL config:staging
1) "host"
2) "db1.example.com"
3) "port"
4) "5432"

The staging config is overwritten with production's values.

Example 3: Copy a key with TTL (and restore TTL manually)

127.0.0.1:6379> SET temp:data "expires soon" EX 60
OK
127.0.0.1:6379> TTL temp:data
(integer) 57
127.0.0.1:6379> COPY temp:data permanent:data
(integer) 1
127.0.0.1:6379> TTL permanent:data
(integer) -1
127.0.0.1:6379> EXPIRE permanent:data 60
(integer) 1

After copy, the new key has no TTL (-1 means no expiration). You must set it manually if needed.

Example 4: Rename a key between Redis databases

127.0.0.1:6379> SELECT 0
OK
127.0.0.1:6379> SET cache:v1 "data"
OK
127.0.0.1:6379> RENAME cache:v1 cache:v2
OK
127.0.0.1:6379> SELECT 1
OK
127.0.0.1:6379> EXISTS cache:v2
(integer) 0

RENAME only works within the same logical database (db0 to db0). To move a key between databases, copy then delete.

Compare options / when to choose what

Scenario Command Why
Fixing a misspelled key RENAME Quick, atomic, keeps TTL
Cloning data for A/B testing COPY Preserves original, no TTL by default (you set new)
Migrating key to a different database (e.g., db0 to db1) COPY + DEL RENAME can't cross databases
Updating a config cache with new values COPY ... REPLACE Avoids the delete-then-set race
Renaming a key that might already exist (safe mode) EXISTS check then RENAME or COPY ... REPLACE Avoids accidental overwrite

Pro tip: If you need to rename a key only if the destination doesn't exist, check with EXISTS first. Redis does not have a conditional RENAME.

Troubleshooting & edge cases

Common mistake: RENAME a non-existent key

127.0.0.1:6379> RENAME nosuchkey newkey
(error) ERR no such key

Always verify the source exists — or wrap in a Lua script if you need conditional logic.

Common mistake: COPY without REPLACE when destination exists

127.0.0.1:6379> SET existing "old"
OK
127.0.0.1:6379> SET source "new"
OK
127.0.0.1:6379> COPY source existing
(integer) 0
127.0.0.1:6379> GET existing
"old"

The copy silently fails — the destination is unchanged. Add REPLACE if overwriting is intended.

Edge case: Renaming a key with a very large value

RENAME is O(1) — it just changes a pointer in the keyspace. The value itself is not moved in memory. COPY, however, must traverse the data structure: O(N) for lists, sets, hashes. Copying a 10-million-element sorted set will block Redis briefly — be aware.

Edge case: TTL inconsistencies

If you rename a key that has a TTL, the new key inherits the remaining TTL. If you copy, the new key gets no TTL by default. If you copy and expect the TTL to be preserved, you must manually re-apply EXPIRE.

What you learned & what's next

You now understand how to rename and copy keys in Redis safely and atomically. You know:

  • The difference between RENAME (destructive move) and COPY (non-destructive duplication).
  • How to avoid race conditions by using server-side commands.
  • That TTL is preserved on rename but lost on copy — and how to restore it.
  • The limitations between databases and with non-existing keys.

This skill is essential for key lifecycle management — especially when you're refactoring code, rotating secrets, or running blue-green deployments. The next lesson dives into key expiration and TTL — you'll learn how to set, inspect, and remove timeouts programmatically.

What's next: Make sure you're comfortable with EXISTS, TYPE, and basic string/hash commands from earlier lessons — you'll need them for the coming exercises on EXPIRE, TTL, and PERSIST.

Practice recap

Practice exercise: In redis-cli, create a hash called cache:prod:user:42 with fields name and role. Rename it to cache:v2:user:42. Then copy it to cache:v2:user:42-backup with a 60-second TTL. Verify both keys exist and have the correct data. Try copying to an existing key without REPLACE — see what happens.

Common mistakes

  • Assuming COPY preserves TTL — it doesn't; you must call EXPIRE on the destination if needed.
  • Using RENAME without checking if the source key exists — leads to 'no such key' error.
  • Forgetting that RENAME overwrites an existing destination key with no warning — unexpectedly losing data.
  • Using COPY without REPLACE when the destination already exists — the command returns 0 silently and nothing changes.

Variations

  1. Use SORT ... STORE to sort a list or set and store the result in a new key (similar to copy + transform).
  2. In Lua scripting, you can implement conditional rename/copy with redis.call('EXISTS') and redis.call('RENAME') for atomic, custom logic.
  3. For moving keys between Redis instances (not databases), use MIGRATE command instead of copy/rename.

Real-world use cases

  • Renaming a key prefix during a service migration (e.g., v1:user:123 to v2:user:123) without stopping traffic.
  • Copying a production feature flag configuration to a staging key for A/B testing, with a different TTL.
  • Implementing a 'key rotation' strategy: rename the active cache key to a backup, then set a fresh key — allows rollback on failure.

Key takeaways

  • RENAME atomically moves a key and its TTL to a new name; the old key is deleted.
  • COPY duplicates a key without removing the original; available since Redis 6.2.
  • COPY does not copy TTL — you must manually set expiration on the destination if needed.
  • Use COPY ... REPLACE to overwrite an existing destination; without REPLACE, the copy fails silently.
  • RENAME only works within the same database; use COPY plus DEL to move a key between databases.
  • Always check key existence before renaming to avoid runtime errors.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.