Microsoft has been signaling the deprecation arc for classic Dataverse workflows for years. Real-time workflows still run, but new investment is in modern flows and async workflow conversion to Power Automate is the safer bet for anything non-critical. Plan the migration before the deprecation timeline forces it.
Inventory first
Pull every workflow in the environment via the workflow table:
GET /api/data/v9.2/workflows?$filter=type eq 1 and category eq 0
&$select=name,uniquename,statecode,primaryentity,mode,_ownerid_value
category 0 is workflows, mode distinguishes sync (real-time) from async. Group by primary entity and execution count (cross-reference asyncoperation for the past 30 days).
You will likely find:
- 30 to 50 percent are inactive
- 10 to 20 percent are duplicates
- 20 percent run rarely and exist for compliance
- 30 percent carry actual production logic
Decommission the inactive and duplicate set first. That is half your migration work for free.
Prioritize by risk and effort
Map remaining workflows on a 2x2:
- Low effort, low risk: trivial field updates, send-email actions. Port first.
- Low effort, high risk: SLA workflows, billing automations. Port carefully with parallel-running validation.
- High effort, low risk: long branching workflows feeding non-critical systems. Schedule mid-program.
- High effort, high risk: case escalation chains, payment processing. Last, with stakeholder sign-off.
Port pattern
For each workflow, build a modern flow using the Dataverse trigger that matches the original step:
- Workflow on Create -> “When a row is added” trigger
- Workflow on Update of Field X -> “When a row is modified” trigger with
Filtering attributesset to X - Workflow on Status Change -> “When a row is modified” with filter expression on
statecode
Match scope: Workflow “Organization” -> trigger scope “Organization.” Workflow “Business Unit” -> add a filter expression in the trigger.
Action mapping:
- Update Record -> Update a Row
- Create Record -> Add a New Row
- Send Email -> Send an Email (V2) via Outlook or Compose Email + Update Email actions for templated mail
- Wait Condition -> Delay or Delay Until plus reload pattern
- Custom Workflow Activity -> rewrite as a custom connector or HTTP-with-Entra action
Run in parallel
For high-risk workflows, do not flip the switch. Activate the modern flow alongside the classic workflow. Both write to a comparison table or log. Run for two weeks. Diff the results. Only then deactivate the classic workflow.
Handle the gotchas
A few migration traps:
- Modern flows do not participate in the same transaction as the triggering operation. A classic real-time workflow that rolled back on failure will not roll back as a flow.
- Modern flow concurrency is per-instance; classic workflow concurrency was per-record. High-volume triggers can cause out-of-order execution.
- Pre/post images do not exist in flows. Use the Dataverse trigger’s “Trigger conditions” and “Select columns” carefully.
Decommission cleanly
After two weeks of parallel runs and zero diffs, deactivate the classic workflow. Wait another two weeks before deleting it; some scenarios run monthly or quarterly and you want to catch the long-tail trigger.
Document the new flows
Each new flow gets a one-page runbook in the same solution: original workflow name, new flow name, business owner, validation method. Future you will need the trail.
What to do this week: pull the workflow inventory, deactivate everything in the inactive bucket, and pick three low-effort low-risk workflows to port as a pilot.