Migrating From Salesforce to Dynamics 365: The Practices That Actually Hold Up
Why "just move the data" is where these projects go wrong
Almost every Salesforce to Dynamics 365 migration that lands in trouble started with the same instinct: export the objects, import them into Dynamics, and worry about the rest later. It sounds efficient. It is the fastest way to a system that technically holds your records and does none of the work you actually run on.
The reason is that Salesforce and Dynamics 365 are not two skins over the same engine. Salesforce organises data as objects with its own metadata, its own automation model in Apex and Flow, and its own security model. Dynamics 365 sits on Dataverse, with tables, columns, relationships, business rules, plugins, and a Power Platform automation layer. The record for an account might look identical in both. The rules that fire when someone edits it, the way it relates to other records, and who is allowed to see it are all built differently. If you copy the data and skip the model, you inherit none of the logic and all of the cleanup.
So the practices worth following are less about import tooling and more about deciding, table by table, what your process should look like once it lives on Dataverse. Here is how we approach it.
Map the model before you move a single row
The first real work is a mapping exercise, not an export. Every Salesforce object you care about gets matched to a Dataverse table: standard objects like Account, Contact, Opportunity, and Case line up reasonably well with their Dynamics equivalents, but the match is rarely one to one. Custom objects, junction objects, and record types all need a deliberate decision about whether they become custom tables, columns on an existing table, or something the out-of-the-box Sales or Customer Service app already models.
This is also where you decide what not to bring. Most long-lived Salesforce orgs carry fields nobody has written to in years, automation that duplicates other automation, and picklists with values that stopped meaning anything. A migration is the one moment where retiring that costs nothing. We audit which fields are actually populated and used, keep those, and leave the rest behind rather than faithfully reproducing a mess in a new home. Getting the target model right is the part of a migration that pays off for years, and it is the core of how our Dynamics 365 and Power Platform services approach this kind of work.
Rewrite the logic onto supported ground
Data is the visible half of a migration. The logic is the half that decides whether the new system behaves. Salesforce automation written in Apex triggers, Process Builder, and Flow does not port to Dynamics 365. It has to be rebuilt, and rebuilt in the right place, which is a chance to consolidate rules that had sprawled across three tools.
The rough translation looks like this. Validation and simple field logic that lived in Salesforce validation rules or formula fields usually becomes a Dataverse business rule or calculated column. Synchronous logic that must block a save belongs in a plugin on the correct pipeline stage. Asynchronous work that can tolerate a few seconds fits a Power Automate flow. Custom Lightning components with genuinely bespoke UI map to PowerApps Component Framework controls, written in TypeScript and React, that run natively inside the model-driven app and read and write through Dataverse. The goal is one rule in one place, not the same rule reimplemented in whatever tool was open at the time.
Migrate in phases and reconcile every one
A big-bang migration where everything moves in one weekend is a bet that nothing will go wrong at the worst possible moment. Phasing is safer and, in practice, faster to recover from. We move data in a sequence that respects relationships: parent records like accounts and contacts before the opportunities and cases that reference them, reference and configuration data before transactional data, so lookups resolve instead of dangling.
Every phase ends with reconciliation, not a vibe check. Row counts on both sides, spot checks on high-value records, and validation that relationships survived the move. Salesforce IDs are worth carrying into a Dataverse column during the migration so you can trace any record back to its origin and re-run a phase without creating duplicates. When a load fails halfway, and one will, that traceability is the difference between a clean retry and a forensic afternoon.
Run both systems together before you cut over
The safest cutover is the one you have already rehearsed with real users. Before switching anyone off Salesforce, we get the Dynamics 365 environment to a state where a pilot team can do genuine work in it, then run a period where the two systems overlap and the new one is proven against the old on live cases. That is also when integrations get tested end to end: the email sync, the telephony, the reporting warehouse, the finance system that was quietly reading from Salesforce and now needs to read from Dataverse.
Migrations in regulated settings, the kind we see in financial services, lean even harder on this overlap, because security roles, field-level access, and audit history all have to be demonstrably correct before the old system goes dark. The dual-run window is where you find the integration nobody documented, while you still have a working fallback.
Treat the new environment like something you will keep
The last practice is the one that keeps a migration from becoming the next rescue project. Everything you build in Dynamics 365, the tables, the business rules, the plugins, the flows, goes into solutions and moves through separate development, test, and production environments rather than being edited live. That is the same solution-based application lifecycle management we bring to every build, and it means the migration ends with a system your team can change safely instead of one nobody wants to touch. You can see the shape of that embedded, extend-what-exists delivery in our field service case study, where the work meant joining a live environment and moving it forward without breaking what was running.
A Salesforce to Dynamics 365 migration is a rebuild of how your team works, wearing the costume of a data transfer. Treated that way, it is very doable. If you want a straight read on what your org would actually take to move, that is the conversation our services are built to start.
A Salesforce to Dynamics 365 migration goes well when you treat it as a rebuild of your process on Dataverse rather than a straight data copy. Map objects to tables deliberately, rewrite Apex and flow logic onto supported ground, migrate in phases with real reconciliation, and run both systems side by side before you cut over. Solzet is a Yerevan-based Dynamics 365 Customer Engagement and Power Platform team that does this kind of migration.
Frequently Asked Questions
What are the best practices for migrating from Salesforce to Dynamics 365?
Treat it as a rebuild on Dataverse, not a data copy. Map each Salesforce object to a Dynamics 365 table deliberately and drop the fields and automation nobody uses. Rewrite Apex, Process Builder, and Flow logic onto supported ground: business rules, plugins, Power Automate flows, and PCF controls. Migrate in phases that respect record relationships, reconcile every phase against row counts and spot checks, and run both systems side by side before cutover. Build everything in solutions so the new environment is safe to change afterward.
Can you migrate Salesforce data directly into Dynamics 365?
You can move the records, but a direct copy brings none of your logic and all of your legacy clutter. Salesforce objects, Apex automation, and its security model do not map one to one onto Dataverse tables, plugins, and Dynamics security roles. A useful migration maps the model first, rebuilds automation in the right place, and carries the Salesforce record IDs into Dataverse so every migrated row is traceable and phases can be re-run without creating duplicates.
How do you handle Salesforce Apex and Flow logic in Dynamics 365?
It gets rebuilt, not ported, and that is a chance to consolidate. Validation and formula logic usually becomes a Dataverse business rule or calculated column. Logic that must block a save belongs in a plugin on the correct pipeline stage. Work that can run asynchronously fits a Power Automate flow. Bespoke Lightning UI maps to a PowerApps Component Framework control in TypeScript and React that runs natively inside the model-driven app. The aim is one rule in one place instead of the same rule spread across several tools.
Should we run Salesforce and Dynamics 365 at the same time during a migration?
A short overlap is the safest way to cut over. Get the Dynamics 365 environment to a state where a pilot team can do real work, then run both systems in parallel so the new one is proven against the old on live cases and every integration is tested end to end. This is where you find the undocumented integration and confirm security roles and audit history are correct, while Salesforce is still there as a fallback if something is missing.