# MIGRATE

> Move one or more keys to another HotKV or Redis server, atomically per key.

URL: https://docs.hotkv.com/commands/migrate/

```
MIGRATE host port key | "" destination-db timeout [COPY] [REPLACE] [AUTH password | AUTH2 username password] [KEYS key [key ...]]
```

- Group: Cluster
- Complexity: O(N) where N is the total size of the keys moved
- HotKV Cloud: all plans
- On-Premise: no license needed

`MIGRATE` copies keys from the current database to another server and, unless
you pass `COPY`, deletes them here once the target has stored them. Each key
moves with its value and its remaining time to live. Resharding uses it to
empty a slot on the source node (see [CLUSTER SETSLOT](https://docs.hotkv.com/commands/cluster-setslot/index.md)),
but it works between any two servers, cluster or not, including a Redis
target.

To move one key, give it as `key`. To move several, pass `""` as `key` and
list them after `KEYS`. Keys that do not exist here are skipped.

The target receives each key with `RESTORE-ASKING`, so it is accepted
whether the target already owns the slot or is still importing it. The
command blocks the calling client until it finishes or fails.

## Options

| Option | Effect |
| --- | --- |
| `host` | The target's IP address or a name the system resolves, such as `localhost`. |
| `port` | The target's client port. |
| `destination-db` | Database on the target (selected there when not 0). |
| `timeout` | Milliseconds allowed for connecting and for each write and read on the target connection. `0` means 1000. |
| `COPY` | Keep the keys here as well. |
| `REPLACE` | Overwrite keys that already exist on the target. |
| `AUTH password` | Authenticate on the target with a password. |
| `AUTH2 username password` | Authenticate on the target as an ACL user. |
| `KEYS key [key ...]` | The keys to move, when `key` is `""`. Must come last. |

## Return value

Simple string `OK` in RESP2 and RESP3 when at least one key was moved, or
when none of the keys exist here. Otherwise one of these errors:

| Case | Error |
| --- | --- |
| Port not from 1 to 65535 | `ERR Invalid port` |
| Negative or non-integer database | `ERR Invalid destination DB` |
| Negative or non-integer timeout | `ERR Invalid timeout` |
| `key` is `""` and there is no `KEYS` | `ERR No keys to migrate` |
| Cannot connect in time, or `host` does not resolve | `IOERR error or timeout connecting to the specified instance` |
| A write to the target failed or timed out | `IOERR error or timeout writing to target instance` |
| A read from the target failed or timed out (also during `AUTH` or database selection) | `IOERR error or timeout reading to target instance` |
| The target refused the password | `ERR Target authentication failed` |
| The target refused the database | `ERR Target SELECT failed` |
| The target refused every key | `ERR ` followed by the target's first error, for example `ERR BUSYKEY Target key name already exists.` without `REPLACE`, or `ERR NOAUTH Authentication required.` when the target needs a password and you gave none |
| In cluster mode, the key's slot belongs to another node | `MOVED slot host:port`, as for any command on that key |

If the target refuses some keys and accepts others, the accepted keys are
moved (and deleted here) and the reply is `OK`. An I/O error stops the
migration; keys moved before it stay moved. The deletions are written to the
AOF and sent to replicas.

## Examples

```
127.0.0.1:6379> SET greeting "hello"
OK
127.0.0.1:6379> MIGRATE 10.0.0.2 6379 greeting 0 5000
OK
127.0.0.1:6379> EXISTS greeting
(integer) 0
127.0.0.1:6379> MIGRATE 10.0.0.2 6379 "" 0 5000 COPY REPLACE KEYS user:1000 {user:1000}:cart
OK
127.0.0.1:6379> MIGRATE 10.0.0.2 6379 "" 0 5000 AUTH2 migrator s3cret KEYS order:77
OK
127.0.0.1:6379> MIGRATE 127.0.0.1 6380 {cart1}:m1 0 1000
(error) ERR BUSYKEY Target key name already exists.
127.0.0.1:6379> MIGRATE localhost 6380 {cart1}:m2 0 1000
OK
127.0.0.1:6379> MIGRATE not-a-host.invalid 6380 {cart1}:m3 0 1000
(error) IOERR error or timeout connecting to the specified instance
127.0.0.1:6379> MIGRATE 127.0.0.1 6381 {cart1}:m4 0 1000 AUTH wrong
(error) ERR Target authentication failed
127.0.0.1:6379> MIGRATE 127.0.0.1 6380 {cart1}:m5 7 1000
OK
```

The last example moved a key to database 7 of the target.

## Compatibility

Same arguments as Redis 7 and Valkey 8. Differences:

- When none of the keys exist, HotKV replies `OK`; Redis replies `NOKEY`.
- An option HotKV does not know is skipped; Redis answers with a syntax error.
- When the target refuses keys, the error carries the target's own error
  text after `ERR`, and a partly successful call replies `OK`.

## See also

[CLUSTER SETSLOT](https://docs.hotkv.com/commands/cluster-setslot/index.md),
[CLUSTER GETKEYSINSLOT](https://docs.hotkv.com/commands/cluster-getkeysinslot/index.md),
[DUMP](https://docs.hotkv.com/commands/dump/index.md), [RESTORE](https://docs.hotkv.com/commands/restore/index.md),
[RESTORE-ASKING](https://docs.hotkv.com/commands/restore-asking/index.md)

In a cluster: [Scaling a cluster](https://docs.hotkv.com/clustering/scaling/index.md#resharding-by-hand)