Home · Blog · Microsoft Fabric

Microsoft Fabric

SQL Server to Microsoft Fabric: why dependency mapping comes first

Every SQL Server to Fabric migration project eventually asks "which workload do we move first?" That's the wrong first question. The right question is: which SQL objects does everything else depend on? The answer to that determines the sequence, the risk, and whether the migration will succeed without an incident.

The migration question nobody asks early enough

A SQL Server data warehouse that's been running for five or ten years doesn't have simple, isolated workloads. It has stored procedures that call views that call other views that reference tables that have been renamed twice since the original developer left. It has cross-database references to reporting databases on the same instance. It has shared utility functions used by 30 different procedures that nobody remembers writing.

When a migration team asks "which workload goes first?", they're usually thinking about business priority, data volume, or team ownership. All valid criteria. But none of them tell you what will break when that workload moves — which is the thing that causes rollbacks, incidents, and project delays.

The dependency structure of the database tells you that. And SQL Server has been building it for you automatically, since 2008.

What SQL Server already knows about your dependencies

sys.sql_expression_dependencies is a catalog view that records every reference one SQL object makes to another. When a stored procedure calls a view, that reference is stored. When a view references a function, that too. Every dependency edge in your database's object graph, recorded automatically, queryable right now on your SQL Server 2016, 2019, 2022, Azure SQL, or Synapse database.

One query to start every Fabric migration planning session:

SELECT
    referenced_entity_name      AS object_name,
    COUNT(*)                    AS caller_count
FROM sys.sql_expression_dependencies
WHERE referenced_database_name IS NULL
GROUP BY referenced_entity_name
ORDER BY caller_count DESC;

Run this on your source SQL Server database. The top of the list — the objects with the highest caller_count — are your highest-dependency objects. These are the objects you migrate last, or handle with the most care, because every object that calls them needs to be verified after the migration.

Objects at the bottom (caller_count of 0 or 1) are candidates to move first, in any order, because nothing depends on them or only a single object does.

Three categories every SQL-to-Fabric migration produces

Once you have the dependency map, workloads naturally sort into three categories:

Category 1

Retire

Objects that appear in the dependency graph but have no callers and no recent execution history. These are dead code — migrate them to Fabric only if you're certain they're still needed.

Category 2

Rehost

Objects with low caller counts and no cross-database dependencies. These can be moved to Fabric Warehouse or Azure Synapse without significant risk, and serve as the first migration wave.

Category 3

Migrate carefully

High-dependency objects — views or functions with 20+ callers, cross-database references, objects called from application code. These move last, after their callers are stable in the new environment.

This categorization is impossible without the dependency map. With it, the migration sequence practically writes itself.

The incremental SQL Server → Fabric path

One increasingly common pattern is an incremental modernization rather than a hard cutover: keep SQL Server (or Azure SQL) as the operational layer while gradually introducing Fabric OneLake and Fabric Warehouse for analytics workloads. This approach reduces risk by allowing parallel running, but it introduces its own dependency challenge: which objects belong on which platform?

The dependency map helps here too. Objects that are purely analytical — aggregations, historical views, reporting procedures — are candidates for Fabric Warehouse. Objects that are transactional, that feed application logic, or that are called from operational stored procedures should stay closer to the SQL Server layer.

Finding those boundaries requires tracing the dependency graph to see which analytical objects are truly isolated from transactional ones, and which are more entangled than they appear.

Cross-database references: the Fabric migration blocker

SQL Server databases on-premises frequently use three-part naming to reference objects in sibling databases (ReportingDB.dbo.vwMonthlyRevenue). This pattern works transparently on a SQL Server instance but doesn't translate directly to Microsoft Fabric Warehouse, which uses a different cross-database access model.

Find every cross-database reference before you commit to a migration plan:

SELECT
    referencing_entity_name         AS calling_object,
    referenced_database_name        AS target_database,
    referenced_entity_name          AS target_object
FROM sys.sql_expression_dependencies
WHERE referenced_database_name IS NOT NULL
ORDER BY referenced_database_name, calling_object;

Each row in this result is a dependency that crosses a database boundary. In a Fabric migration, each of these needs an explicit resolution — either consolidating objects into the same Fabric Workspace, using Fabric shortcuts, or rewriting the references.

Finding these on day one of the migration project is far less painful than finding them on cutover day.

Dynamic SQL: the gap in the catalog view

One important caveat: sys.sql_expression_dependencies does not capture references inside dynamic SQL strings. A stored procedure that builds a query with EXEC() or sp_executesql and calls another object inside that string will not show up as a caller in the dependency view.

On heavily dynamic SQL codebases — common in older data warehouses that used dynamic SQL for parameterized reporting — the catalog view will undercount dependencies. Complement the catalog analysis with:

What to do with the dependency map

Once you've run the analysis, the dependency map supports several artifacts that make the rest of the migration project easier:

None of these require anything beyond the catalog view queries above and a spreadsheet. They represent the pre-migration analysis phase that most teams skip because it feels less tangible than running the migration tools — and then discover they needed when something breaks in the new environment.

See the dependency graph visually. Skupa reads sys.sql_expression_dependencies live from Azure SQL, SQL Managed Instance, and Azure Synapse and renders the full call graph as an interactive swimlane diagram. Export to Visio, CSV, or JSON for the migration planning documents.

Download free trial

The dependency map is a migration prerequisite, not a nice-to-have

SQL Server to Fabric migrations fail most often not because the target platform doesn't support the workload — it usually does — but because the migration team didn't know what the workload depended on before they moved it. A view breaks because a function it calls wasn't migrated in the same wave. A procedure fails because it references a database that wasn't included in the migration scope. A report breaks because the object it queries was renamed during the migration as a "quick cleanup."

Every one of those incidents shows up in sys.sql_expression_dependencies before the migration happens. The catalog view is already there, on your running SQL Server 2016 database, populated with the complete dependency graph. It takes one query to read it.

← Back to blog · sys.sql_expression_dependencies deep dive →