GOVERNANCE · April 15, 2026 · 11 min read
Before you migrate a SharePoint site, find every flow, app, and Teams tab that depends on it
Here is the script nobody wants to live through. On Friday you migrate a SharePoint site. The cutover is clean. Permissions replay, pages render, the document libraries are right. You close the ticket. Monday morning there are seven tickets open, all of them variations of “this thing that used to work is broken now.” You start digging. One is a Power Automate flow that fires when an item is added to a list that no longer lives at the URL the trigger was configured against. One is a canvas Power App whose data source connector is still pointed at the old site GUID. Two are Teams tabs that show Cannot load content because the tab was pinned to a SharePoint page at the old URL. One is an embedded Power BI report that references a SharePoint list as a datasource. Two are approval flows fired from library views that are now 404.
None of this was in your migration scope document. Nobody mentioned the flows. The person who built the app left two years ago. The Teams tab owner is on leave. You spend the next three days playing detective while the users are unhappy and the client is unhappier.
This is the silent breakage problem, and it is the single largest source of “the migration technically succeeded but the project failed” outcomes in SharePoint work. The migration tool does its job. Nobody told the tool about the web of Power Platform artefacts quietly referring to the site’s URLs and list GUIDs. The Power Platform Dependency Graph exists to fix this. Before you migrate, you scan. Everything that depends on the site shows up in a single table. You decide what to update, what to rebuild, and what to warn the owner about. Then you migrate.
What the scanner actually looks for
The scanner lives at /governance/dependencies in MigrationFox. You point it at a SharePoint site (hostname + site path, or a root site collection), and it walks four artefact classes across your tenant:
- Power Automate cloud flows. We enumerate flows in every environment the authenticated principal can see via the Business Application Platform (BAP) API —
https://api.bap.microsoft.com/providers/Microsoft.BusinessAppPlatform/scopes/admin/environments, then/flowsunder each. For each flow we inspect the trigger and action definitions for SharePoint connectors and extract thesiteUrl,listId, andtableparameters. - Power Apps (canvas and model-driven). We enumerate apps via the same BAP API, then pull the
unpackedDefinition(for canvas) or the connection references (for model-driven) to find SharePoint datasource bindings. Canvas app definitions are zipped JSON trees; we unpack and scan forSharePointdatasource entries that include the site hostname or list identifier. - Teams tabs and channel messages. Via Graph (
/teams/{id}/channels/{id}/tabs) we read every tab’sconfiguration.contentUrlandconfiguration.websiteUrl. SharePoint page tabs, document library tabs, and list tabs all encode the site URL directly. - SharePoint-hosted artefacts on the site itself. Modern pages that embed list views, web parts referencing other sites, and document library lookups that cross site boundaries. These are read through the standard SharePoint REST API.
Power BI is on the roadmap for v2. The BI admin API needs different scoping to inspect dataset lineage, and the match-quality characteristics are different enough that we are shipping it as its own module.
Match strength: exact, possible, heuristic
Not every reference is created equal. A flow that names the site as https://contoso.sharepoint.com/sites/finance directly in the trigger config is an exact match — we know with certainty the flow will break if that site URL changes or the underlying list GUIDs change. A flow that references a list GUID without the site URL is still an exact match because GUIDs are tenant-unique. But a flow action that constructs a URL by concatenating variables (concat(parameters('siteBase'), '/Lists/', variables('listName'))) is a heuristic match — we can see the shape of the URL the action will build at runtime, but not always the final value.
The scanner classifies every finding into one of three buckets:
- Exact — the artefact references the site URL or a list GUID owned by the site. Will definitely break on migration unless updated.
- Possible — the artefact references the site tenant or a parent path, but the specific list/page binding is dynamic. Likely to break. Needs a human to look.
- Heuristic — the artefact contains string fragments that match the site (e.g., the site name appears in a flow’s variables or a tab’s display name). May or may not break. Worth flagging but not blocking.
The UI shows all three in one table with the match type as a coloured pill, so you can scan for exact first, fix those, then triage the rest. The reason the heuristic bucket exists at all is that Power Automate flow action URLs are often constructed at runtime from workflow variables — the tool cannot execute the flow just to inspect the bound URL. We surface the action, the variable name, and the containing string so a human can assess in thirty seconds instead of three hours.
The per-artefact table
Every finding becomes a row. Each row has:
- Artefact type (Flow / App / Teams Tab / Site Web Part)
- Artefact name and owner
- Environment (Power Platform) or Team (Teams)
- Last modified date — useful for deciding “is this even live?”
- Last run date for flows — if a flow has not run in 18 months, it is probably abandoned
- Match type (exact / possible / heuristic)
- The specific reference (trigger, action, datasource, tab URL) that tied the artefact to this site
- A “fix after migration” column where you can type the new URL or GUID before cutover
You can export the whole table as CSV and hand it to the client as the pre-migration dependency document. The standard workflow: run the scan, attach the CSV to the change ticket, and have the business owner sign off on “these ten flows will need to be repointed on cutover day.”
How to use it
- Open
/governance/dependenciesin MigrationFox. - Connect your tenant if you have not already. The scanner needs Graph
Sites.Read.All,Flow.Read.All(BAP),Group.Read.All(for Teams enumeration), andPowerApp.Read.All. Read-only across the board. - Paste the source SharePoint site URL. The scanner accepts either
https://contoso.sharepoint.com/sites/financeor the root collection. - Click Scan dependencies. Expect about 2 minutes per 100 flows and 30 seconds per 50 apps. Teams tabs are fast — typically under a minute for a tenant with a few hundred teams.
- Review the table. Sort by match type. Fix the
exactrows first. - Export CSV. Share with the business owner and the app owners. Track sign-off in your migration change ticket.
- During the migration cutover, apply URL and GUID updates to the listed flows and apps. For Teams tabs, either update the
contentUrlvia Graph (PATCH /teams/{id}/channels/{id}/tabs/{id}) or delete-and-recreate the tab pointing at the new URL.
A worked example
Real numbers from an engagement last month. The client was consolidating four regional SharePoint site collections into a single hub. Before the migration, scope of Power Platform dependencies according to the client: “maybe two or three flows, there is a canvas app somewhere.” After running the dependency scan:
| Artefact | Found | Exact | Heuristic |
|---|---|---|---|
| Power Automate flows | 47 | 31 | 16 |
| Power Apps (canvas) | 8 | 6 | 2 |
| Power Apps (model-driven) | 2 | 2 | 0 |
| Teams tabs | 23 | 23 | 0 |
| SharePoint cross-site web parts | 14 | 14 | 0 |
Of those 47 flows, 11 had not run in over a year and were quietly decommissioned. Of the active 36, seven were owned by the CFO’s assistant who had no idea she was a citizen developer. The scan turned a one-sentence scope assumption into a real dependency inventory in 12 minutes of scanner runtime.
What v1 does not do yet
Honest list, no vapourware:
- Power BI dataset lineage. Scheduled for v2. Requires a different admin API scope and match logic.
- Desktop flows (Power Automate for desktop). Not scanned. These live on user machines and are not enumerable via the tenant API.
- Logic Apps. Out of scope for the Power Platform module. If you need Logic Apps inventory, use Azure Resource Graph.
- Azure Functions and custom code that calls the Graph API against SharePoint. No way to enumerate this without source code access.
- SharePoint Framework (SPFx) extensions. The tenant-wide app catalogue is readable, but scanning individual SPFx bundles for hardcoded URLs is v2.
- Flow action URL matching. Currently heuristic when URLs are built from variables. Improving this is a backlog item; it would require a partial expression evaluator.
The point of surfacing this list here is the same as the point of the heuristic match bucket: a tool that hides its limits is worse than a tool that names them. You know exactly what the scan covers and where you still need a human pass.
Why this matters for the migration contract
Fixed-price SharePoint migrations historically carry all the silent-breakage risk on the delivery side. The contract says “migrate site X,” the client assumes everything downstream will keep working, the post-cutover breakage eats the margin. With a dependency scan attached to the pre-migration change document, the risk allocation shifts: the client signs off on a concrete list of flows and apps that will need updating, and those get scoped as separate line items. The scan is free to run; the fix work bills normally.
The right sequence is: scan first, scope against the scan, migrate last. Flip that order and you are debugging flows on a Monday morning with users asking when their app will be back.
Related reading
- SharePoint migration best practices: pre-flight, cutover, post-verify
- The Power Platform governance assessment
- How MigrationFox cut SharePoint migration time by ~50%
Get started
Run your first dependency scan at app.migrationfox.com/register. Read-only Graph and BAP scopes; results in minutes.