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
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.).
RENAMEchanges the label on the box. After rename, the old label no longer exists. If the new label already exists, its box is destroyed first —RENAMEis an overwrite operation.COPYcreates a second label pointing to a new box with a duplicate of the original data. The original box stays untouched.COPYis 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:
RENAMEis always dangerous if you're not sure about the destination. If you need to keep the original key, useCOPY.
How it works step by step
RENAME execution flow
- You send
RENAME oldkey newkey. - Redis checks if
oldkeyexists. If not, an error is returned. - If
newkeyalready exists, Redis atomicallyDELetes it. - The value (and its TTL) from
oldkeyis moved tonewkey. oldkeyis removed from the keyspace.
COPY execution flow
- You send
COPY source destination [DB destination-db] [REPLACE]. - Redis checks if
sourceexists. If not, returns 0. - If
destinationalready exists: - WithoutREPLACE: command returns 0 (no copy). - WithREPLACE:destinationisDELeted first. - The value from
sourceis durably copied todestination. TTL is not preserved by default (the new key has no TTL unless you set it after). - Returns 1 on success, 0 on failure.
Blockquote callout:
COPYdoes not copy the TTL of the source key. If you need the same expiration, you must set it on the destination after the copy usingEXPIRE.
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
EXISTSfirst. Redis does not have a conditionalRENAME.
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) andCOPY(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 onEXPIRE,TTL, andPERSIST.
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
COPYpreserves TTL — it doesn't; you must callEXPIREon the destination if needed. - Using
RENAMEwithout checking if the source key exists — leads to 'no such key' error. - Forgetting that
RENAMEoverwrites an existing destination key with no warning — unexpectedly losing data. - Using
COPYwithoutREPLACEwhen the destination already exists — the command returns 0 silently and nothing changes.
Variations
- Use
SORT ... STOREto sort a list or set and store the result in a new key (similar to copy + transform). - In Lua scripting, you can implement conditional rename/copy with
redis.call('EXISTS')andredis.call('RENAME')for atomic, custom logic. - For moving keys between Redis instances (not databases), use
MIGRATEcommand instead of copy/rename.
Real-world use cases
- Renaming a key prefix during a service migration (e.g.,
v1:user:123tov2: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
RENAMEatomically moves a key and its TTL to a new name; the old key is deleted.COPYduplicates a key without removing the original; available since Redis 6.2.COPYdoes not copy TTL — you must manually set expiration on the destination if needed.- Use
COPY ... REPLACEto overwrite an existing destination; withoutREPLACE, the copy fails silently. RENAMEonly works within the same database; useCOPYplusDELto move a key between databases.- Always check key existence before renaming to avoid runtime errors.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.