WuKongIM Docs

v2 → v3 Offline Migration

Follow a single-node cluster example through cold backup, planning, migration, startup, acceptance, and cutover.

This walkthrough migrates users, credentials, conversations, and messages from original v2 into a fresh v3 single-node cluster. Follow the steps in order: back up → write a plan → migrate → start and test → cut over.

For multi-node clusters, use the three-node plan in the migration reference. Include every source node and run the migration centrally on one machine; do not take just one node's data from a multi-node cluster.

The environment for this example

This example uses a separate Linux migration machine that also runs v3 after migration. It excludes plugins and external integrations. Rehearse in isolation first.

ItemExample value
Original v2Original v2.2.5-20260422, single-node cluster, node ID 1001
Original business DB shard count8; replace with the actual value from the old configuration
Stopped v2 serverSSH hostname v2-a, complete data directory /opt/wukongim/data
Cold backup on the migration machine/srv/v2-snapshots/node1001/data
Migration working directory/srv/wkmigrate; must be a new directory
Target v3Node ID 1, RPC address 127.0.0.1:7001
Target data directory/srv/wkmigrate/targets/node1; created by the migration tool

Replace the v2 hostname, original data path, node ID, and shard count with your actual values. You can keep the remaining example paths. Run the commands in a Bash terminal on the migration machine with permission to write under /srv.

Confirm three things before starting:

  • All sources are stopped and the target is a fresh empty cluster. v3 cannot open v2 data directories directly, and online incremental migration is not supported.
  • Follow wkcli installation to obtain matching wkcli and wukongim binaries and verify the delivered checksums. The current documentation version is v3.0.0-beta.21. For other v2 versions, custom builds, plugins, or external integrations, read the compatibility requirements first.
  • Allow disk space for complete cold backups, workspaces, the archive, target data, and pre-start snapshots. Rehearse to measure peak space and total duration before scheduling the production maintenance window.

1. Take a complete cold backup

On the original deployment, stop business write ingress, wait for log application, topology changes, and notification queues to drain, then stop v2 gracefully and disable automatic restarts. Preserve the old binaries, configuration, and environment variables. The directory copied below must no longer be changing. Do not copy a running database.

On the migration machine, run:

umask 077
mkdir -p /srv/v2-snapshots/node1001/data
rsync -a --numeric-ids --partial \
  root@v2-a:/opt/wukongim/data/ /srv/v2-snapshots/node1001/data/

After copying succeeds, verify the copy:

rsync -anc --numeric-ids --delete --itemize-changes \
  root@v2-a:/opt/wukongim/data/ /srv/v2-snapshots/node1001/data/

Pass condition: exit code 0 and no file differences. Here, -n makes verification a dry run that deletes nothing. Keep the trailing /; include the whole directory and hidden files. If you already have a complete cold backup, copy from that backup without restarting v2.

You can restore original v2 service after taking the rehearsal backup. For production cutover, stop writes and all sources again, take a fresh backup, and repeat the remaining steps in new working directories. Writes made during rehearsal do not automatically enter the earlier migration output.

2. Save the migration plan

First check the tools:

wkcli version --output json
wukongim version --output json

Both binaries must have identical version, commit, and build_source values. Then create the working directory. If /srv/wkmigrate already exists, choose a new path and update the following paths consistently; do not overwrite an earlier attempt.

mkdir /srv/wkmigrate && mkdir -p /srv/wkmigrate/{reports,work,targets}

Save this as /srv/wkmigrate/plan.json, updating the source node, shard count, and creation timestamp for this attempt:

{
  "version": 1,
  "source_commit": "a888f89533d0e7d1b2030e06504ca97f1ad891d4",
  "sources": [
    {"node_id": 1001, "data_dir": "/srv/v2-snapshots/node1001/data", "shard_count": 8}
  ],
  "target": {
    "cluster_id": "migration-v3-new",
    "created_at": "2026-09-12T00:00:00Z",
    "slot_count": 12,
    "hash_slot_count": 256,
    "replicas": 1,
    "channel_replicas": 1,
    "nodes": [
      {"node_id": 1, "addr": "127.0.0.1:7001", "data_dir": "/srv/wkmigrate/targets/node1"}
    ]
  }
}

source_commit selects the supported v2 reader schema. Keep this value; it is not a guessed image version. The target uses 12 physical Slots, 256 hash slots, and one replica. All paths are absolute paths on the migration machine and must not contain one another. Do not create targets/node1 beforehand.

This plan does not enable deduplication, CMD/stream exclusion, or sequence renumbering. If compatibility checks block migration, use the troubleshooting section below rather than applying data-discard policies just to pass validation.

3. Run migration and reach offline_verified

Keep v3 stopped. Run this command block once on the migration machine. A failed stage stops the block immediately; reports are saved under reports.

(
  set -e
  umask 077
  wkcli migrate prepare --plan /srv/wkmigrate/plan.json \
    --workspace /srv/wkmigrate/work/prepare \
    > /srv/wkmigrate/reports/prepare.json 2> /srv/wkmigrate/reports/prepare.stderr
  wkcli migrate export --plan /srv/wkmigrate/plan.json \
    --workspace /srv/wkmigrate/work/prepare --archive /srv/wkmigrate/source-archive \
    > /srv/wkmigrate/reports/export.json 2> /srv/wkmigrate/reports/export.stderr
  wkcli migrate import --plan /srv/wkmigrate/plan.json \
    --workspace /srv/wkmigrate/work/import --archive /srv/wkmigrate/source-archive \
    > /srv/wkmigrate/reports/import.json 2> /srv/wkmigrate/reports/import.stderr
  wkcli migrate verify --plan /srv/wkmigrate/plan.json \
    --workspace /srv/wkmigrate/work/verify --archive /srv/wkmigrate/source-archive \
    > /srv/wkmigrate/reports/verify.json 2> /srv/wkmigrate/reports/verify.stderr
  cat /srv/wkmigrate/reports/verify.json
)
StagePurposePass condition
prepareCheck cold backups and prepare conversionExit code 0, report says prepared
exportSeal original data into an archiveExit code 0, archive contains COMPLETE
importGenerate v3 data directoriesExit code 0, report says imported
verifyIndependently compare target data against the original archiveExit code 0, report says offline_verified

cutover_ready: false is expected. Offline data verification has passed; runtime and business acceptance still follow. Preserve the cold backups, archive, plan, and all reports.

4. Start v3 and test real business behavior

First startup changes the databases. Save a snapshot of the verified targets before they have ever started. In this example, check that the snapshot path does not exist, then run:

test ! -e /srv/wkmigrate/targets-before-start && \
  cp -a /srv/wkmigrate/targets /srv/wkmigrate/targets-before-start && \
wukongim config init --config /srv/wkmigrate/wukongim.toml

Confirm the snapshot copy succeeded, and save the administrator password displayed during initialization. Edit the generated wukongim.toml, changing these two values while preserving all other settings and generated secrets:

Configuration locationChange to
data_dir under [node]"/srv/wkmigrate/targets/node1"
id under [cluster]"migration-v3-new"

Check that generated values match the plan: node.id=1, cluster.listen_addr="127.0.0.1:7001", cluster.nodes=[{id=1,addr="127.0.0.1:7001"}], initial_slot_count=12, hash_slot_count=256, slot_replica_n=1, and channel_replica_n=1. Keep gateway.token_auth_on=true. If original v2 used whitelistOffOfPerson=false, also set message.person_whitelist_enabled=true.

Confirm that no leftover WK_ environment variables override these values, then validate and start in the foreground:

wukongim config validate --config /srv/wkmigrate/wukongim.toml && \
  wukongim -config /srv/wkmigrate/wukongim.toml

Keep that terminal open. In another terminal on the migration machine, check:

curl --fail http://127.0.0.1:5001/readyz

After /readyz succeeds, test these four areas with your actual client or the Chat Demo. Default listeners use loopback addresses; for remote access, use SSH forwarding as described in Linux deployment.

  • Login works: use the original UID, Token, and matching device_flag. Incorrect tokens must be rejected. Do not register again and overwrite original credentials.
  • Old data matches: check early, recent, and cross-page person/group history, including payloads, message IDs, sequences, conversation lists, and read/unread state.
  • Messaging continues: send new messages on isolated rehearsal data. Check receipt, unread counts, retry deduplication, and new sequences greater than the channel's current tail.
  • Data survives restart: stop v3 gracefully, start it again, and recheck history, new messages, and unread state.

Write acceptance in this example is for rehearsal. Production migration also requires acceptance, but run write tests on isolated copies and keep production targets free of business writes until cutover. Started directories cannot be verified as the initial import state or overwritten by another import.

5. Cut over production

After rehearsal, repeat migration during the production maintenance window using fresh complete cold backups and new working directories. Complete offline verification and runtime/client acceptance. Keep original v2 writes stopped. Run v3 under a service manager following Linux deployment, confirming it uses the verified configuration and the same data directory. Then point business backend and client connection/routing endpoints to v3 and gradually restore traffic.

If you enabled sequence renumbering from the reference, also handle client history caches and sync cursors during cutover. Preserve login credentials and handle unsent messages and drafts first. The tool does not clear client caches automatically.

v2 and v3 must never accept writes for the same business simultaneously. Before v3 accepts new production writes, you can close v3 ingress and restore original v2 data, binaries, and routing using the rehearsed procedure. Afterward, switching directly back to old v2 would lose new data. The tool has no reverse incremental v3 → v2 migration.

If a step fails

For example, if prepare fails, read these two files first:

cat /srv/wkmigrate/reports/prepare.stderr
cat /srv/wkmigrate/reports/prepare.json

Use the corresponding filenames for other stages. Preserve the failed attempt and logs. Do not rerun the entire block and overwrite reports, delete source data, or alter markers to force a pass.

SituationNext action
Target directory already existsCheck whether it belongs to an earlier migration. Use a new path for a first attempt; follow the reference for retries
Plugin, duplicate message, conversation, or replica conflictsRead the report and resolve each issue using the migration reference
No output for a long time, or context canceledCheck stage progress in .stderr, process status, disk space, and outer timeouts. Do not start a second concurrent migration
Multi-node, Docker, or deployment to other serversUse the plans, directory distribution, and startup configuration in the migration reference

The migration reference contains full retry conditions, plugin policies, data transformations, and business acceptance checks. Consult it for the situation you encounter.

On this page