← All posts

Move Data to Another SeaweedFS Cluster from the Admin UI

4 min read SeaweedFS Team

SeaweedFS Enterprise Data Movement keeps a filer path in sync with a destination — another SeaweedFS cluster, or a cloud object store (S3, GCS, Azure, B2). You point a policy at a source path and a named target, pick a mode, and data_movement plugin workers do the rest: an initial snapshot seeds what’s already there, then a tail of the metadata log carries every change as it happens. It’s all managed and monitored from the Admin UI.

This post runs it end to end on two real clusters. Every command and screenshot is from that session.

Admin UI policies · targets · monitoring schedules Source SeaweedFS filer + volumes a path, e.g. /data data_movement worker ① initial snapshot ② tail the metadata log bounded · resumable slices per-policy lease + fence Target SeaweedFS cluster filersink · optional mTLS Cloud object store S3 · GCS · Azure · B2 read write via sink modes: continuous · migrate (cut-over) · backup
What we're building: a continuous policy replicating a source filer path to a destination cluster, run by a data_movement worker.

Step 1 — Two clusters and a worker

Bring up a source cluster (with the Admin UI) and a destination cluster on separate ports. weed mini is the all-in-one; the destination just needs its filer to receive writes:

# source cluster (Admin UI on :23646, filer gRPC :18888)
weed mini -dir=./src  -admin.port=23646

# destination cluster (the move target; filer gRPC :18988)
weed mini -dir=./dest -admin.ui=false \
  -master.port=9433 -volume.port=9440 -filer.port=8988 -s3.port=8433

Data movement runs on plugin workers, so start one pointed at the source’s admin:

weed worker -admin=127.0.0.1:23646

Data movement is opt-in — it consumes cluster bandwidth and cloud APIs — so enable the data_movement job type once in the Admin UI’s plugin configuration (or via its API). Then seed some data on the source to replicate:

weed filer.copy -c 8 ./files/*.txt http://127.0.0.1:8888/data/
# source /data now holds 20 files

Step 2 — Register the destination as a target

On the Admin UI’s Data Movement → Targets page, add a target. A target is a reusable named destination — a SeaweedFS cluster (its filer gRPC address) or a cloud store via a remote.configure credential:

The SeaweedFS Admin UI Movement Targets page: a Registered Destinations table with one entry, dr-cluster, kind 'cluster', destination 127.0.0.1:18988 path /data, using default gRPC credentials, used by 1 policy.
The target dr-cluster — the destination cluster's filer at 127.0.0.1:18988, writing under /data. Cloud targets pick a remote.configure record instead.

Step 3 — Create a continuous policy

On the Policies page, create a policy binding the source path to that target. We pick Continuous mode and turn on the initial snapshot so the 20 files already in /data get seeded (a policy without a snapshot starts from now and only carries new changes).

The worker detects the policy, takes the lease, snapshot-seeds the existing tree, and starts tailing. Within seconds the destination has everything:

source /data: 20 files   →   dest /data: 20 files
status: phase=caught_up  walked=20  moved=20  lag=0s

Step 4 — Watch it stay in sync

Continuous means it keeps going. Write more files to the source, and the metadata tail carries them across:

weed filer.copy -c 4 ./more/*.txt http://127.0.0.1:8888/data/   # +5 files
source /data: 25 files   →   dest /data: 25 files
filesMoved: 25   bytesMoved: 108095   lagSeconds: 0

The Policies page shows it live — mode, phase, replication lag, and how much has moved:

The SeaweedFS Admin UI Movement Policies page: summary cards showing 1 policy (1 enabled), 105.6 KB moved (25 files), worst lag 0s, 0 needing attention; a table row for policy replicate-data moving /data to dr-cluster:/data in CONTINUOUS mode, phase Caught up, 0s lag, 25 files / 105.6 KB moved.
Caught up: 25 files (105.6 KB) replicated from /data to dr-cluster, zero lag — 20 from the initial snapshot, 5 from the continuous tail.

That’s the whole loop: seed, then tail, with the destination staying current.

What just happened

  • The worker ran bounded, resumable slices. It committed its seed cursor before tailing, so a slice that dies resumes from the same point; a per-policy lease fences out stale workers. A slice ends at its deadline, on config change, or on lease loss, and detection re-proposes the next one — a dataset larger than one slice seeds fully instead of restarting.
  • The mode decides the behavior. Continuous mirrors indefinitely; Migrate adds a cut-over fence that confirms the destination has everything before you flip traffic (lag=0 alone isn’t “done”); Backup keeps deletes off so the destination retains what the source removed.
  • The target could have been the cloud. Swap the cluster target for an S3, GCS, Azure, or B2 destination and the same policy replicates to object storage instead — one system to run for cross-cluster and cross-cloud movement.

See the Data Movement docs for the architecture, the modes, cloud targets, and the safety model (leases, verify-sink, evidence-based cut-over).