Migrating a live member community without leaking anyone
Moving a legacy member community the safe way: 600+ submissions but fewer than 30 hand-published members, then private drafts, fresh consent, reversible records, and phased invitation waves.
TL;DR
Migrating a member community is not a database copy — it’s a consent and reversibility problem. When you move real people’s profiles from an old platform to a new one, the failure mode isn’t a bad import; it’s publishing someone before they agreed to be published.
The pattern that made migrating 600+ legacy submissions safe: import everyone as private drafts, capture fresh consent + eligibility on the new platform, tag every record for rollback, and roll out invitations in phased waves with monitoring between each.
This complements the member directory case study — that one is about the live product; this note is about getting a legacy community into it without breaking anyone’s trust.
The starting point: a manual bottleneck
The legacy WordPress site had 600+ submissions but fewer than 30 members actually visible in the directory. Not because people weren’t applying — because publishing a member was a manual step: an admin hand-added each approved person to the members list. The backlog was the workflow.
So the migration wasn’t just “move the data.” It was “replace the manual bottleneck with a self-service flow”: members log in, edit their own profile, and an approval flips them live — instead of an admin re-typing everyone. Automating that publish step is what turned a sub-30 trickle into something that could actually onboard the 600+ backlog.
The trap: “migration” sounds like “copy”
A legacy site already has everyone’s data — bios, photos, business details — so the tempting move is to import it and switch the new directory on. That quietly does something you never had permission to do: it re-publishes people on a new platform, under new terms, in a new searchable place, without asking.
Old consent doesn’t transfer. Consent given to a WordPress directory in 2019 is not consent to appear in a new Shopify-hosted directory in 2026. Treat the migration as a new publication event, because legally and ethically that’s what it is.
The rule: import private, publish on consent
Every imported record lands as a private draft and stays private until the member does four things on the new platform:
- Logs in (proves control of the account).
- Confirms eligibility (still a member in good standing).
- Gives fresh consent to be listed.
- Is approved by an operator.
Only when all four are true does the profile become public. Until then it’s invisible to the directory query and excluded from search engines. The import gets the data ready; the member decides if it goes live.
This maps cleanly onto the directory’s existing moderation model — a draft/published split where the published copy is the only thing the public ever sees.
Build the importer to be boring: resumable and idempotent
A one-shot script that dies at record 400 is a disaster, because now you don’t know what’s half-done. The importer was built to be re-runnable without fear:
- Idempotent — running it twice doesn’t create duplicates; it converges to the same state.
- Resumable — it can stop and restart, picking up where it left off.
- Auditable — it emits a machine-readable report of exactly what it created, skipped, and why.
- Tested against messy reality — property-based tests (fast-check) threw malformed, missing, and weird inputs at it, because 600+ hand-entered records will contain surprises.
The goal isn’t a clever importer. It’s an importer you can run at 2pm, get interrupted, and re-run at 4pm without holding your breath.
Make every record reversible
Before importing anything, decide how you’d undo it. Every migrated record was tagged so the entire batch can be identified and rolled back as a unit. “We can always undo this” changes how fast you can move — reversibility is the safety margin that lets you ship.
If you can’t cleanly answer “how do we roll this back?”, you’re not ready to import.
Roll out invitations in waves, not a broadcast
The migration invitation — the email that tells members “we’ve moved, come claim your profile” — is the riskiest single action, because it hits everyone at once and touches deliverability, load, and trust.
So it went out in waves:
- A small canary wave first, watched closely (deliverability, bounces, confused replies, error rates).
- Then progressively larger waves, with monitoring between each.
- Lifecycle emails (received / approved / changes published) wired up before the invitation, so members got feedback at every step instead of silence.
A blast to 660 people is one big bet you can’t take back. Waves turn it into a series of small, observed bets — and the first sign of trouble stops the rollout instead of reaching everyone.
Keep the old site up until the new one earns the switch
The public relaunch — new theme, structured data, accessibility fixes, legal policies — shipped as a zero-downtime domain cutover, not a hard swap. The legacy host stayed authoritative until the new site was proven, then the domain moved. No window where members hit a broken or empty site.
Key lessons
- A community migration is a consent event, not a data copy — old consent doesn’t transfer to a new platform.
- Import private, publish on fresh consent — the import prepares data; the member decides if it goes live.
- Make the importer idempotent, resumable, and auditable — you want to re-run it without fear, not pray it finishes.
- Tag for rollback before you import — if you can’t undo it cleanly, you’re not ready.
- Phased waves beat a broadcast — a canary first, monitoring between waves, and the ability to stop before everyone’s affected.
- Keep the old system authoritative until the new one earns the cutover.
The one-line version
Don’t migrate people. Invite them — and keep everyone private until they say yes.