Migrating from a flat to an N-level structure β
Most churches start with a flat structure β everyone is just a "member," there's one site, and the org chart is in someone's head. That works until the second campus opens, the first cell-group leader needs a scope, or the elders want demographic breakdowns by region.
This page walks through the migration: from a single-tier organization (or a legacy three-level branch/center/bascenta setup) to the N-level model GCM uses today.
Two starting points β
You're probably in one of these positions:
- Brand-new GCM org with one level defined. You added a few units at level 1 (or just left the default Branch level seeded) and now you want to add levels 2 and 3 without disturbing the members already on level 1.
- Existing GCM org from before N-level shipped. Your data is already in
org_unitsβ the legacy three-level model was migrated over by GCM during a platform update. You don't need to migrate the data; you might want to rename or restructure.
Both follow the same shape. Differences are called out where they matter.
The migration shape β
- Audit what you have. List every existing unit and the count of members assigned.
- Design the target tree on paper. Decide level names, which existing units become which new units, and where members land.
- Add new levels in Settings. Levels first, units second.
- Create the new units. Start at the top level and work down.
- Reassign members. Move them off level 1 onto the appropriate leaf level.
- Archive the old units if they're no longer needed.
- Re-scope users so shepherds see the right slice.
- Sanity-check reports before announcing.
You can do this incrementally β there's no "migration mode." The org keeps running through the whole thing.
Step 1: audit β
Open the Org Structure page and write down every active unit. Note the member count badge on each. Export the members list filtered by unit (/members?org_unit=<id>) to CSV if you want a paper trail.
Things to flag:
- Units with zero members β candidates for deletion before you start.
- Units with no leader β candidates for fixing while you're in there anyway.
- Duplicate-named units under different parents β easy to mix up during reassignment.
Step 2: design the target β
Sketch the new tree before touching the UI. A common target:
Branch (level 1)
βββ Center (level 2)
βββ Cell (level 3)For each existing unit, decide which leaf-level unit its members will end up on. If everyone is currently on level 1 ("Acacia Branch") and you're adding cells, you need to know which cell each member joins. That's a decision for your team, not for GCM.
Document the mapping in a spreadsheet:
| Current unit (level 1) | New unit (level 3) | Member count |
|---|---|---|
| Acacia Branch | Acacia Cell A | 45 |
| Acacia Branch | Acacia Cell B | 38 |
| Acacia Branch | Acacia Cell C | 22 |
Step 3: add new levels in Settings β
Go to Settings β Org Hierarchy and add the levels you don't have yet. See Defining levels for the field-by-field walk-through.
Name them how your church speaks. Save. Don't worry about unit creation yet β the levels just need to exist.
Step 4: create the new units β
Open the org tree. Expand the level 1 unit you want to nest under. Use the three-dot menu to add child units one level down. Repeat for level 3.
For a lot of units at once, drill into the level page (/hierarchy/2) and add them card-by-card. It's faster than the dialog dance on the tree.
Set addresses and map locations as you go β the map module will populate as soon as the geocoder catches up.
Step 5: reassign members β
This is the part where most churches lose patience. Two options:
Option A β one unit at a time, in the UI β
- Open the new cell's detail page.
- Click Add member, search, pick, confirm.
- Repeat for each member that belongs to the cell.
Slow but visible. Good for small orgs (< 100 members).
Option B β bulk via the members list β
- Go to Members and filter to the cell's intended members (by name, by visitor status, by whatever).
- Select all rows.
- Bulk actions β Assign to unit β pick the cell.
GCM upserts the assignments. Existing level-3 rows get replaced; if level 1 was already set, that row stays untouched. (To clear level 1 in bulk too, run Unassign from level 1 first.)
For large migrations, you can also bake the unit assignment into a one-off CSV import, but you'd be re-importing data that's already in the system β usually more work than the bulk action.
Reassignment is one-per-level, not many-per-unit
A member at level 1 with no level-3 assignment gets a new level-3 row added β nothing replaced. But a member already on level-3 Acacia Cell A who you reassign to Acacia Cell B replaces the row. The unique index guarantees no doubles.
Step 6: archive the old units β
If your old level-1 Acacia Branch still has members directly assigned to it after the migration, you have two paths:
- Leave them there. Members on the branch level still cascade up correctly. Your roll-up reports keep working.
- Move them off with Bulk actions β Unassign from level 1 and let them sit at leaf level only.
You probably don't want to archive level 1 Acacia Branch β it's still your top-level unit, just now with descendants. But if you're really restructuring (e.g. Acacia Branch and Maple Branch merge into Tree Branch), see Archive and restore for the cascade rules.
Step 7: re-scope users β
Shepherds you'd previously scoped to Acacia Branch now see the entire Acacia subtree by default. If that's what you want, no action.
If you want a cell leader scoped only to their cell:
- Go to Users & Roles β Users and open the user.
- Click Edit assignments.
- Untick the branch-level assignment and tick the cell-level one.
- Save.
The next page load picks up the new scope. See Assigning leaders and shepherds for the full model.
Step 8: sanity-check β
Before you announce the change to your team, verify:
- Total member count on the dashboard matches what you had before.
- Per-branch member count matches the sum of its descendants.
- A shepherd's login shows their cell's members only.
- Last week's attendance report still resolves β historical events use the unit id, which didn't change.
- The map shows the new units pinned at their addresses.
Mismatches usually trace to leftover level-1 assignments you didn't realize were there. Re-export the members list, sort by unit, and look for blanks.
What you don't have to migrate β
The legacy three-level branch/center/bascenta column model is fully removed from app code as of the latest platform update. If your old data references those columns, GCM already migrated the rows into org_units during the upgrade. The labels were preserved as level 1, 2, 3 with the original names. You don't need to do anything to "complete" the migration β the new model is the only model.
Type-system references to the legacy columns survive in src/integrations/supabase/types.ts because that file is auto-generated from the database, and the columns weren't dropped. The app ignores them.
Common questions β
Can I do this migration in stages over weeks? Yes. There's no "switch flip." You can add level 2 today, level 3 next month. Just make sure members are placed before any report relies on the new structure.
What happens to existing attendance and giving rows that reference the old units? They're keyed by unit id, not level. As long as the unit id exists (whether at level 1 or as a renamed entity), the row still resolves. Archiving or deleting the old unit is what would break historical reports β so do that with care.
Should I delete or archive after the migration? Archive. Always archive. You can always change your mind and unarchive; deletion is final from the UI.
Next steps β
- Define levels β set up the target tier names.
- Create units β populate the new levels.
- Assign members β reattach people to the right leaves.
