CRM migration guide

The Definitive Guide to Migrating to Microsoft Dynamics 365 Sales

Dynamics 365 Sales sits on top of Dataverse and the Power Platform, which means a migration is really five projects — schema modelling, security roles, server-side automation, client scripts, and an environment-promotion plan — running in parallel.

23 min read 9 sections Updated May 27, 2026
Microsoft Dynamics 365 Sales
Contacts
Companies
Deals
Leads
Activities
Notes

Inside this guide

What you'll learn, section by section

  1. 01

    Why teams migrate to Microsoft Dynamics 365 Sales

    The four shapes a Dynamics 365 Sales migration takes, and what makes the platform harder — or easier — than the category average.

  2. 02

    The Dataverse data model you need to map into

    Tables, columns, relationships, and the alternate-key mechanics you will wire on every field — the destination schema decoded.

  3. 03

    Pre-migration prep — the work before you touch Dynamics 365 Sales

    What must be true on the source, the destination, and across the team before the first row hits the Data Import Wizard.

  4. 04

    Import mechanisms: Data Import Wizard and SSIS

    The load paths in, each with different limits and shapes. Picking the wrong one is how mid-migrations stall at scale.

  5. 05

    Mapping your data into Dynamics 365 Sales

    The longest section — because field mapping is where almost every migration that fails actually breaks.

  6. 06

    The pitfalls that derail Dynamics 365 Sales migrations

    Nine specific failure modes — ranked by impact, each tied to the exact Dataverse mechanism that breaks.

  7. 07

    Validation and cutover

    What to verify after the import job, in what order — and how to fail safely when something is wrong.

  8. 08

    Migration partners and tools

    Microsoft Solutions Partners, ETL connectors, specialist Dataverse shops — what each is good for and how to choose.

  9. 09

    Frequently asked questions

    The eight questions every Dynamics 365 Sales migration team works through before they sign the scope.

Section 01

Why teams migrate to Microsoft Dynamics 365 Sales

The four shapes a Dynamics 365 Sales migration takes, and what makes the platform harder — or easier — than the category average.

Microsoft Dynamics 365 Sales is the sales application inside Microsoft's broader Dynamics 365 business-applications suite, sitting alongside Customer Service, Field Service, Customer Insights and Finance & Operations. All of them store their data in Dataverse — the Microsoft-managed relational layer formerly called the Common Data Service — and run on top of the Power Platform 111.

The typical Sales customer is a mid-market or enterprise revenue team that already lives inside Microsoft 365: Outlook for email, Teams for collaboration, SharePoint for documents, Azure AD for identity. Compared with Salesforce Sales Cloud, Dynamics 365 Sales positions on Microsoft-native integration and Copilot reach into Office; compared with HubSpot or Pipedrive, it positions on enterprise-grade extensibility through plug-ins and Power Automate flows 5.

The shapes of migration that actually land on Dynamics 365 Sales tend to fall into four patterns. First, Salesforce exits, driven by total cost of ownership at the Enterprise tier and by teams that want their CRM closer to Microsoft 365 and Power BI. Second, on-premises Dynamics CRM cloud moves, where customers running Dynamics CRM 2015/2016 or Customer Engagement on-premises shift to the online Dataverse-backed product.

Third, consolidation projects: a business standardising on the Microsoft stack and replacing Pipedrive, HubSpot, Zoho or homegrown systems with Sales plus Customer Service plus Customer Insights on a single Dataverse. Fourth, M&A integration, where an acquirer pulls the acquired company off a different CRM onto its existing Dynamics environment. A Salesforce exit has rich automation that does not move as code; an on-prem Dynamics move has clean schema but old plug-ins that need rewriting against the current platform.

What makes migrating *to* Dynamics 365 Sales harder than the category average is the platform's extensibility surface. There are five places business logic can live — Business Process Flows, classic Workflows, server-side Plug-ins, Power Automate cloud flows, and client-side JavaScript — and a migration has to decide which layer rebuilds each piece of legacy logic.

Add Dataverse security roles, Business Units and Teams on top, and the schema is only half the project. The native Data Import Wizard caps individual files at 8 MB (32 MB for .zip) and Microsoft itself recommends limiting import jobs to 20,000 rows — anything bigger is supposed to go through SSIS, not the wizard 1314.

What makes it easier is template-based imports straight from the system, mature duplicate-detection rules across Accounts, Contacts and Leads, and a Dataverse model that already speaks the standard CRM vocabulary — Lead, Account, Contact, Opportunity, Quote, Order, Invoice96. Teams that scope the five automation layers and the security model up front finish on time; teams that treat it as a CSV-shaped project do not.

Schema is half the project. Security roles, plug-ins, flows and Business Process Flows are the other half.

Section 02

The Dataverse data model you need to map into

Tables, columns, relationships, and the alternate-key mechanics you will wire on every field — the destination schema decoded.

Microsoft platform Contacts Companies Deals Tickets Tasks Notes
Standard objects orbit the platform; every association can be many-to-many with optional labels.

Dynamics 365 Sales does not have its own data layer. Every record lives in a Dataverse table (formerly called an entity), and Sales ships a curated set of standard tables that the application's forms, views and Business Process Flows are bound to 111.

Before you can map a single column you need to know which Dataverse table the row belongs on, what columns are required, and which value will serve as the alternate key for upsert. The table below summarises the tables you will touch in a Sales migration.

Object Stores Required on import Tier
Lead Unqualified inquiry — pre-Opportunity record Topic (subject); one of First Name + Last Name or Company All Sales SKUs
Account Organisations — customers, prospects, partners Account Name (primary name) All Sales SKUs
Contact Individual people associated with Accounts or Leads Last Name All Sales SKUs
Opportunity Active deal in pipeline; replaces Lead at qualify Topic, Potential Customer (Account or Contact) All Sales SKUs
Quote / Order / Invoice Customer-facing pricing, sales orders, billed invoices Name, Price List, Opportunity (for Quote) Sales Enterprise+
Product / Price List Item Catalogue of sellable items and tier pricing Product Name, Unit Group, Default Unit Sales Enterprise+
Activity (Phone Call, Email, Appointment, Task, Letter) Timeline events linked to Leads, Contacts, Opportunities Subject, Regarding, Activity Type All Sales SKUs
Annotation (Note) Free-text notes with optional file attachment Subject, Regarding (Object Type Code + ID) All Sales SKUs
Custom tables Customer-defined records inside the same Dataverse Primary name column; per-column requirements All SKUs (storage tier applies)

Every Dataverse record has a system-generated GUID (accountid, contactid, opportunityid) which is the canonical primary key. For migrations, the practical upsert key is an alternate key — a column you mark as unique on the table definition, then use as the entity reference when upserting.

Set up alternate keys on Account (often the legacy crm_source_id or website domain), Contact (legacy ID or email), and any custom table before the first row goes in — adding an alternate key after data exists requires Microsoft to build a unique index across what may now be a millions-of-rows table. The column catalogue below covers what you can model and the limits you need to plan around.

Field type Limits Notes
Single Line of Text Up to 4,000 chars per column Email, phone, URL, ticker subtypes available
Multiple Lines of Text Up to 1,048,576 chars Stored as nvarchar(max); Rich text is opt-in
Whole Number / Decimal / Float / Currency Decimal: 10 precision; Currency uses Exchange Rate Decimal is exact, Float is approximate — pick deliberately 53
Date and Time / Date Only UTC-stored; per-column behavior User Local vs Date Only Behavior cannot be changed after data exists in some cases
Choice (Option Set) / Choices (Multi-select) Global vs local; integer value per label Internal integer value, not the label, is stored
Lookup Up to 50 explicit lookups per table (practical guidance) Each lookup is a foreign key to a target table's primary ID
Calculated / Rollup Max 10 unique calculated fields per table; max 10 rollups per table Calculated runs at retrieve; rollup runs on schedule (hourly+)
Columns per table 1,000 fields per entity online; 1,023 on legacy on-prem Custom + system combined — model defensively from day one

Relationships in Dataverse come in three shapes. One-to-Many (parent-child, e.g. Account → Contact) supports configurable cascading behaviour: on delete, you can choose Cascade All, Cascade Active, Cascade User-Owned, Remove Link or Restrict 45. Many-to-One is the inverse, exposed as a lookup column on the child. Many-to-Many is supported natively but stores the relationship in a hidden intersect table that is read-only to external loads — for editable many-to-many you create a manual junction table with two lookups 43.

Custom tables participate in relationships the same way standard tables do, including the same cascade options and lookup mechanics. Microsoft Dataverse storage is consumed in three pools — Database (relational rows), File (attachments) and Log (audit) — and the tenant allowance scales with licensed users; teams importing legacy attachments need to size File storage explicitly because it is the pool that fills first.

Section 03

Pre-migration prep — the work before you touch Dynamics 365 Sales

What must be true on the source, the destination, and across the team before the first row hits the Data Import Wizard.

The single best predictor of a clean Sales migration is how much work you do on the source side before the first import job is queued. Microsoft's own Dataverse guidance is explicit: skipped or rushed testing is one of the most common reasons migrations fail, and the fix is almost always pre-processing rather than post-cleanup.

Treat the source export as raw material that needs to be shaped to Dataverse's expectations — option-set integer values, alternate keys, owner-resolved-to-Azure-AD users, dates in ISO-8601, currencies aligned to the exchange rate.

Source-side prep

  • Audit and dedup the source database before export. Dynamics 365 publishes default duplicate-detection rules for Accounts, Contacts and Leads, but practitioner guidance is to dedup *before* import so the rules act as a safety net, not the first line of defence.
  • Resolve option-set values to integers, not labels. Every Choice column stores an integer; the label is for display. The wizard will accept some labels via auto-match but programmatic loads expect the integer and fail silently when the label is wrong-cased.
  • Stamp a stable external ID on every record in the source export — the source platform's primary key or a UUID — so you can wire an alternate key on the Dataverse table and re-runs are deterministic.
  • Normalise currencies and exchange rates. Dataverse stores an Exchange Rate per Transaction Currency record; if your source had multi-currency data without a rate column, decide whether you import in base currency or pre-create Transaction Currency rows with historical rates.
  • Decide what is in scope for historical activities. Phone Calls, Emails, Appointments, Tasks and Letters can be imported with a backdated *Actual End* timestamp, but each one carries the same write cost as a record create 66.

Destination-side prep

  • Design the environment strategy — Default, Production, Sandbox, Developer — and pick which one is the data-migration environment. Microsoft explicitly recommends a dedicated data-migration environment because it is a disruptive task that cannot coexist with other testing activities 34.
  • Provision users in Azure AD / Entra ID first, assign Dynamics 365 Sales licences, then map them into Dataverse security roles before importing. Owner assignment during import fails silently if the referenced user is not yet a Dataverse user.
  • Build security roles, Business Units and Teams before importing. Owner-based row security is enforced at retrieve, not at write — get this wrong and reps see records they should not, or miss records they should.
  • Pre-create every custom table and column with the correct data type, including alternate keys, calculated/rollup formulas, and Choice option sets with stable integer values.
  • Build the Solution. Wrap your customisations in an unmanaged Solution in the development environment, then export as managed and deploy to the migration and production environments — this is the ALM pattern Microsoft documents for Power Platform 11.

People prep

Cutover only works if humans cooperate. Lock down a source-system freeze window — typically 48 to 96 hours for mid-market — and communicate it to every department that touches the CRM. Train sales reps on the Sales Hub model-driven app, Business Process Flows and Outlook + Teams integration before go-live. Microsoft's own guidance pegs small-to-mid migrations at 8 to 12 weeks of elapsed time, with enterprise programmes running 6 to 12 months end-to-end.

Section 04

Import mechanisms: Data Import Wizard and SSIS

The load paths in, each with different limits and shapes. Picking the wrong one is how mid-migrations stall at scale.

Dynamics 365 Sales exposes several load paths and the right one depends on row count, table mix, and whether the load needs to be re-runnable. The Data Import Wizard covers small-to-medium one-shot migrations under 20,000 rows per job. SSIS with KingswaySoft (or equivalent) and the Data Migration Framework sit on top and add transformation, staging and resume-on-failure semantics.

Data Import Wizard

The native import lives in the model-driven app under Settings → Data Management → Imports, or via Advanced Find → Import Data on supported entity grids 13. Supported file formats: CSV (.csv), Text (.txt), Compressed (.zip), Excel Spreadsheet 2003 (.xml) and Excel Workbook (.xlsx). The maximum file size is 8 MB for individual files and 32 MB for .zip bundles 1314. A .zip can include multiple CSV/XML/TXT files and an optional Attachments folder, all imported as a single job.

The wizard supports a Map Automatically mode that matches columns to table fields by header name, and an explicit Data Map mode that lets you save and reuse mappings across imports. Templates exported from Settings → Templates for Data Import give pre-built XML spreadsheets with the right columns for Accounts, Contacts, Leads and other standard tables. The right call: wizard for one-shot loads under 20,000 rows on standard tables.

SSIS, KingswaySoft, and the Data Migration Framework

For enterprise-scale loads, the most common stack is SQL Server Integration Services (SSIS) plus the KingswaySoft Dynamics 365 connector. SSIS handles transformation, staging tables and resume-on-failure; the connector wraps the Dataverse write path with batch-size tuning, error-row routing and built-in lookups 150. The Data Migration Framework (DMF) inside Power Platform admin is the Microsoft-native ETL equivalent and handles configuration data and reference-data loads through entity maps that include concatenation, split and replace transformations 14.

Workato, Fivetran, Azure Data Factory and Power Automate are also commonly used in two ways: reverse-ETL where the source platform is staged into Azure SQL or Synapse, transformed in T-SQL, then synced into Dataverse; and ongoing-sync where the tool takes over once the one-time migration is complete.

Rule

Under 5,000 records on standard tables → Data Import Wizard. 5,000–20,000 → Wizard with templates, in batched files. Over 20,000, any custom tables, or any re-runnable load → SSIS+KingswaySoft, or the Data Migration Framework.

Section 05

Mapping your data into Dynamics 365 Sales

The longest section — because field mapping is where almost every migration that fails actually breaks.

SOURCE MICROSOFT DYNAMICS 365 SALES FirstName, LastName firstname, lastname AccountName company AnnualRevenue annualrevenue Owner.Email hubspot_owner_id CreatedDate createdate
Field-mapping flow — every source field resolves to a destination property or an explicit drop.

Mapping is where every migration earns its scars. The schema decisions you make in your mapping spreadsheet determine whether reports work on day two, whether Business Process Flows fire correctly on day five, and whether your sales team trusts the data on day thirty.

Work table by table, top to bottom of the import order: Transaction Currencies first, then Users and Teams, then Accounts (so Contacts and Opportunities can point at them), then Contacts, then Leads, then Opportunities, then Activities, then Annotations and attachments, then custom tables, then Quote/Order/Invoice if in scope 150.

Accounts

Common source → Dynamics 365 Sales Account mapping

Source Destination
  • company_name
    name (primary name)

    Required; max 160 chars on the standard column

  • website / domain
    websiteurl

    Plain URL; not used by default duplicate-detection but recommended for an alternate key

  • owner / account_owner
    ownerid (lookup to systemuser)

    Pre-resolve to Azure AD user; assigned to the Business Unit of that user

  • industry
    industrycode

    Choice — store the integer, not the label

  • annual_revenue
    revenue

    Currency type; respects transactioncurrencyid + exchangerate

  • parent account
    parentaccountid (lookup to account)

    Second-pass update after all accounts are loaded

  • legacy_id
    Custom alternate-key column (e.g. crm_legacy_id)

    Mark the column unique; this is your re-run upsert key

Contacts and Leads

Sales treats Lead and Contact as distinct tables, not a single dual-status record. A Lead represents an unqualified inquiry; on qualify, the Lead can be converted into an Account, Contact and Opportunity together 106146. Decide before mapping whether your source's lead-stage records become Dataverse Leads or Contacts — most migrations split on a *Stage = Qualified* flag.

Common source → Dataverse Contact mapping

Source Destination
  • first_name / last_name
    firstname / lastname

    lastname is required; firstname optional

  • email
    emailaddress1

    Lowercase; default Contact duplicate-detection rule keys on this

  • phone
    telephone1

    E.164 recommended; column is single line of text

  • account_id
    parentcustomerid (customer lookup)

    Polymorphic — lookups both Account and Contact tables

  • owner
    ownerid

    User or Team reference; resolve against Azure AD email

Opportunities and the Business Process Flow

Opportunities in Sales are not just a record — they are a record bound to a Business Process Flow (BPF) with stages such as Qualify, Develop, Propose and Close 106149. The BPF is the visible pipeline-stage indicator on every Opportunity form. When you import an Opportunity you set its statecode (Open / Won / Lost) and statuscode (sub-status), and separately set its position on the BPF via the processid and stageid columns.

If you skip the BPF columns the Opportunity loads but appears at stage 1 of whatever the default Lead-to-Opportunity Sales Process is. For multi-pipeline source systems (Pipedrive, Salesforce, HubSpot), recreate each pipeline as its own custom BPF in Dataverse first, then map source-stage → BPF-stage as part of the Opportunity load.

Common source → Dataverse Opportunity mapping

Source Destination
  • deal_name / opportunity_name
    name (Topic)

    Required

  • amount / value
    estimatedvalue

    Currency type; pair with transactioncurrencyid

  • close_date
    estimatedclosedate

    Date Only behaviour by default; UTC-stored

  • stage
    stageid + statuscode

    stageid points at a BPF stage row; do not import label text

  • account / company
    parentaccountid

    Required for forecasting roll-up

  • primary contact
    parentcontactid

    Optional but recommended for activity timeline

  • won/lost
    statecode + statuscode

    Won = 1/3, Lost = 2/4 by default; check your environment's options

Custom-field mapping strategy

Resist the urge to map every source custom field one-to-one. Migrate only the columns used by an active process or report in the last 12 months. Dataverse caps tables at roughly 1,000 columns combined system + custom; once a table is past 600–700 columns the form load times degrade noticeably, and reports built on Dataverse views start hitting the 50-column projection limit.

For Choice columns whose source values do not match, either extend the destination option set with the missing integer values, collapse adjacent values during transform, or introduce a parallel custom column that holds the legacy value verbatim. Calculated and Rollup fields do not import data — Dataverse recomputes them on retrieve or on schedule. Source formulas rebuild as Dataverse calculated fields, and rollup values worth preserving go into a *Legacy Rollup* number column at import time 59.

Historical activities — Phone Calls, Emails, Appointments, Tasks

All five Activity types accept backdated timestamps via the actualend (completed activities) or scheduledend (planned) columns. The visible Timeline date on a Contact or Opportunity reads from modifiedon, not actualend, which catches most teams — the import stamps modifiedon to today and the historical activity appears at the top of the timeline rather than at its true date 84.

The fix is to explicitly set modifiedon during import (it is overridable with a privileged service principal) and set overriddencreatedon to the original create date — Dataverse documents this column specifically for backdated migrations 66. Activity rows also need an activitypartylist payload to attach the From/To/Cc parties; that party list references either a contact, lead, account or systemuser, and missing references silently drop the activity reference from the timeline.

Files and attachments — Annotations and SharePoint

Attachments in Sales live in the Annotation (note) table — each Note has an optional documentbody (base64 binary), filename, mimetype and filesize. Annotations are associated to a parent record via the objectid + objecttypecode columns. The Data Import Wizard accepts Notes inside a .zip with an /Attachments subfolder; the wizard reads the binary and creates the Annotation row in one pass.

For estates above a few gigabytes the supported pattern is SharePoint integration: enable SharePoint document management in Settings → Document Management, point it at a SharePoint Online site, and store attachments as SharePoint files linked to the Dataverse record rather than as Annotation documentbody blobs. This pushes the storage cost off the Dataverse File pool and onto Microsoft 365 file storage. Tools like Inogic Attach2Dynamics handle bulk-migration of historical Annotations to SharePoint or Azure Blob in one pass.

Audit trail, ownership and original timestamps

Dataverse stamps createdon, createdby, modifiedon and modifiedby on every row. These are overridable on import under specific conditions: the calling identity must have the prvOverrideCreatedOnCreatedBy privilege, and you set the overriddencreatedon column rather than createdon directly 83. Standard non-privileged imports get today's timestamp and the importing user as createdby, which silently breaks reports filtered by Created Date.

Owner assignment during import works only if the referenced user or team exists in Dataverse at the moment of write. Rows whose owner cannot be resolved are imported with the importing user as owner, which silently leaks records to anyone whose security role includes that owner's Business Unit 85.

Account-level audit logging is enabled per-table under Settings → Auditing; once on, the audit table records every Create, Update and Delete with previous and new values88. Audit data counts against the Log storage pool, which is separate from Database and File storage but still tier-bound — heavy backfill of historical audit rows is not recommended; capture the source-system audit trail into custom *Legacy Audit* columns instead.

CRM-specific: duplicate detection, sequences, server-side sync

Dynamics 365 ships default duplicate-detection rules for Account (name), Contact (email) and Lead (name + email domain) and lets you author custom rules under Settings → Data Management → Duplicate Detection Rules 96100. Microsoft's recommendation during import is to disable duplicate detection on the load and re-enable after, because each duplicate check is a synchronous query that throttles bulk-load throughput badly 13.

Sequences (the cadence tool inside Sales Insights) do not have an import mechanism — recreate the structure manually and apply to active leads/opportunities post-cutover. Lead-scoring models likewise do not import; rebuild as predictive lead scoring inside Sales Insights or as a custom Dataverse score column 111.

Server-side synchronisation with Exchange Online for email and calendar is configured per user under Settings → Email Configuration → Mailboxes, and should be enabled *after* the historical activity import, not during — otherwise the connector backfills against the same Activities you just loaded and creates duplicates 144.

Section 06

The pitfalls that derail Dynamics 365 Sales migrations

Nine specific failure modes — ranked by impact, each tied to the exact Dataverse mechanism that breaks.

High impact

Choice column labels imported instead of integer values

Every Dataverse Choice column — industrycode, statuscode, customertypecode, every custom Option Set — stores an integer, not the label. The label is Manufacturing; the underlying value might be 7. The Data Import Wizard tolerates label auto-match when casing is exact, but programmatic loaders reject label-only payloads with the unhelpful An attribute cannot be set error. Build your transform layer against the option-set integer values, never against what an admin sees in the UI.

High impact

createdon overridden requires explicit privilege and column

Standard createdon, createdby, modifiedon are Dataverse-managed and ignored unless the caller has the prvOverrideCreatedOnCreatedBy privilege and writes to the overriddencreatedon column, not createdon directly 83. Teams discover this on day two when reports filtered by *Created On* return everything stamped to import day. Mitigation: grant the privilege to the migration service principal, populate overriddencreatedon from the source export, and rewrite all historical-period views to use that column. 83

High impact

Data Import Wizard 8 MB / 32 MB / 20,000-row ceilings

The wizard caps individual files at 8 MB and .zip archives at 32 MB, and Microsoft itself recommends limiting any single job to 20,000 rows for reliable error-handling 1314. Teams that fold a 100,000-row Account file into the wizard discover the import succeeds but the per-row error log is truncated, and a partial-success retry is harder to scope than a fresh load. Anything above the recommendation belongs on SSIS or the Data Migration Framework. 14

Medium impact

Activity timeline ordering breaks without overriddencreatedon

The Activity Timeline on Contacts, Leads and Opportunities sorts by modifiedon descending — not actualend. Importing historical Phone Calls, Emails and Appointments with backdated actualend but default modifiedon makes every imported activity appear *above* live activity, in import order rather than true chronology 84. Set overriddencreatedon and explicitly set modifiedon through the privileged path, then verify a 30-row sample on the Timeline before bulk-running. 84

Medium impact

Calculated and rollup fields silently empty after import

Calculated fields recompute at retrieve time, so they appear correct after import — but rollups recompute on schedule (default hourly with a 12-hour delay on environment-wide jobs) and look empty for hours after import. There is a per-table ceiling of 10 unique calculated fields and 10 rollups, which catches teams porting a Salesforce schema with dozens of formula fields. Capture pre-migration rollup values into a *Legacy Rollup* number column on import to preserve historical reporting until Dataverse recomputes.

Medium impact

Tenant-to-tenant moves require Microsoft FastTrack engagement

Dynamics 365 Sales has no self-service tenant-to-tenant migration button. A full move — including Solutions, customisations and data — requires either: (a) exporting Solutions and re-importing into the new tenant plus an SSIS data lift, or (b) opening a Microsoft FastTrack engagement to coordinate the move 52137. Teams discovering this mid-project after acquisition or rebrand lose 4–8 weeks of elapsed time waiting on the FastTrack queue. Plan tenant strategy before any acquisition closes. 52

Low impact

Storage tier exhaustion from Annotation attachment binaries

Annotation documentbody blobs count against the Dataverse File storage pool, which is tier-bound and bills overage at list prices 105. Importing historical attachments inline via .zip can consume the entire File allowance in a single load. The recommended pattern is SharePoint document management, which keeps file content in Microsoft 365 storage where most tenants already have headroom. Decide the storage architecture before bulk-importing Notes with attachments — switching after the fact requires the Attach2Dynamics-style bulk migration tool.

Section 07

Validation and cutover

What to verify after the import job, in what order — and how to fail safely when something is wrong.

1 Read-only Source goes write-frozen 2 Final delta Export incremental changes 3 Import Load into Microsoft 4 Validate Reconcile + spot-check 5 Cut over Users on new system
Cutover sequencing — five gated phases between source read-only and full user access.

Validation is the bridge between the import finishing and users being allowed in. Microsoft's FastTrack guidance recommends three stages: a 10 percent test load into a sandbox with stakeholder spot-checks, the full load into the migration environment with real-time monitoring of record counts and relationship integrity, and a 30-day post-migration data-quality audit driven by the audit table142. Have department reps verify their own records — they know what right looks like.

Build a reconciliation queries spreadsheet that compares source and destination on each of these counts. Anything outside a 0.5 percent variance gets investigated before users get login access.

  • Total Accounts imported vs source — minus deliberately excluded rows (test accounts, soft-deleted records, opt-outs).
  • Total Contacts imported vs source, with a count of Contacts where parentcustomerid is null — those are unassociated and should match an explicit list.
  • Total Opportunities per pipeline + BPF stage, plus sum of estimatedvalue per pipeline — a non-trivial currency variance signals a stage-mapping error or a missing Transaction Currency Exchange Rate.
  • Total Activities per type (Phone Call, Email, Appointment, Task, Letter) imported vs source — and a date-bucketed comparison against overriddencreatedon to confirm backdating round-tripped.
  • Relationship counts — Contact→Account, Opportunity→Account, Activity→Regarding by object-type-code — checked against source-derived expected counts.
  • Owner distributionGROUP BY ownerid and confirm no record landed under the migration service principal that should not have.
  • Alternate-key integrity — count distinct values on each custom alternate-key column; any duplicates indicate the dedup transform missed cases.

On top of reconciliation, run a manual spot-check protocol: pick 30 random records across tables and verify each field against the source UI. Pick five high-value Opportunities and trace the full graph — Account, Contacts, Quote, Activities, Annotations. If a non-trivial discrepancy shows up in three or more of the 30, halt the load, fix the root cause, and re-import the affected rows by their alternate-key column.

Dynamics 365 supports a partial rollback on imports: under Settings → Data Management → Imports, each import job appears as a row with a Delete option that lets you delete only the records created by that import, leaving everything else intact 114. This is the closest thing to native bulk-undo, but it is import-job-scoped — deletes only the records that job created, and only if they have not been modified since.

The real rollback strategy remains: export everything to Azure Blob or SharePoint before the import starts, stamp every imported row with an *Import Batch ID* custom column, and if catastrophe strikes, bulk-delete by that batch ID via Advanced Find or a Power Automate flow and re-import from the cleaned source.

Cutover sequencing: (1) source goes read-only and the team is notified; (2) final delta export captures everything that changed during the dry-run window; (3) delta is imported via the Data Import Wizard or SSIS; (4) reconciliation runs; (5) users get login access and a 48-hour hyper-care window with the migration lead on call; (6) source decommission is scheduled for 30 to 90 days out, never the same day.

Section 08

Migration partners and tools

Microsoft Solutions Partners, ETL connectors, specialist Dataverse shops — what each is good for and how to choose.

The Microsoft Solutions Partner programme tiers partners by capability and customer count, with a specialisation badge for Business Applications that signals Dynamics 365 depth 123. For Sales migrations specifically, partners with explicit Salesforce-to-Dynamics, on-prem-to-online, or HubSpot-to-Dynamics practices tend to ship cleaner than generalist implementation shops.

Cobalt, Rand Group, Arctic IT, Encore Business Solutions, ProServeIT, SingleStone and Veelead are commonly named in the migration corner of the market and each offers fixed-scope migration packages alongside ongoing managed services. Microsoft also runs its in-house FastTrack for Dynamics 365 service which provides architecture guidance and remediation support at no cost for qualifying customers — useful for tenant-to-tenant moves and large enterprise programmes 123.

On the ETL and iPaaS side, KingswaySoft's SSIS Dynamics 365 connector is the de facto standard for enterprise migrations 150. Fivetran, Workato, Azure Data Factory, Power Automate and Microsoft's own Data Migration Framework all have Dataverse connectors that handle staging, transformation and ongoing sync. Their role is rarely the migration itself — it is the staging layer that lands source data into Azure SQL or Synapse, and the ongoing-sync layer once the one-time load is done.

Managed-migration cost ranges vary widely with scope. A small-business Sales Professional implementation with 10 users, minimal customisation and a one-time CSV import of Accounts and Contacts lands around $4,000–$8,000 in published practitioner estimates 131. Mid-market and enterprise Dynamics 365 CRM implementations — Sales plus historical data, Power Platform automation and Office 365 integration — run $25,000 to over $250,000, driven by record count, custom-table complexity and integration rebuild surface.

For teams that want to outsource the migration end-to-end, FlitStack specialises in Dynamics 365 Sales migrations and handles the Dataverse schema modelling, alternate-key design, option-set integer conversion, BPF stage mapping, server-side privilege configuration for overriddencreatedon, and the reconciliation work described in Sections 5 and 7. Pricing is fixed-fee, scoped by record count and source platform, with separate line items for custom tables, historical Activity depth and SharePoint attachment volume so scope is transparent.

This is one of several legitimate paths — the right choice for any given team depends on whether they want a Solutions Partner with industry depth, a Microsoft FastTrack engagement, an SSIS-led iPaaS approach, or a specialist migration vendor. Explore FlitStack →

Section 09

Frequently asked questions

The eight questions every Dynamics 365 Sales migration team works through before they sign the scope.

References

Sources

  1. 1 Microsoft Dynamics 365 Sales — Wikipedia
  2. 5 Microsoft Dynamics 365 Sales vs Salesforce Sales Cloud — Gartner Peer Insights
  3. 11 Dynamics 365 environment strategy — Microsoft Learn
  4. 13 Import accounts, leads, or other data — Microsoft Learn (Dynamics 365)
  5. 14 Import data (all record types) — Power Platform | Microsoft Learn
  6. 23 Execute Batch Operations on Dataverse — Microsoft Learn
  7. 24 Batch/Bulk operation when upsert is disabled — Dynamics 365 Community
  8. 25 Service protection limits (Microsoft Dataverse)
  9. 30 Extensibility Guide for Dynamics 365 Sales — Microsoft Learn
  10. 34 Get guidance for your Dynamics 365 environment strategy — Microsoft Learn
  11. 43 How to create junction object between two entities — Dynamics 365 Community
  12. 45 Entity relationship behavior — Microsoft Learn
  13. 52 Migration of Dynamics 365 Sales from tenant to new tenant — Dynamics 365 Community
  14. 53 Types of fields and field data in Dynamics 365 — Microsoft Learn
  15. 59 Create a calculated field in Dynamics 365 — Microsoft Learn
  16. 66 Migrating Historical Activities to a new CRM Instance — Dynamics 365 Community
  17. 83 Import accounts, leads, and more into Dynamics 365 Customer Engagement (on-premises)
  18. 84 Override created on date for bulk note import migration — Dynamics 365 Community
  19. 85 Bulk change of owner and record update on filtered accounts — Dynamics 365 Community
  20. 88 audit EntityType (Microsoft.Dynamics.CRM) — Microsoft Learn
  21. 96 Enable duplicate lead detection — Microsoft Learn
  22. 100 Create duplicate detection rules in Dynamics 365 — Microsoft Learn
  23. 105 Dataverse capacity-based storage details — Microsoft Learn
  24. 106 Understand the sales process — Microsoft Learn (Dynamics 365 Sales)
  25. 111 Dynamics 365 Sales documentation — Microsoft Learn
  26. 114 How to roll-back a re-import of accounts — Dynamics 365 Community
  27. 123 Dynamics 365 Partners — Microsoft Dynamics 365
  28. 131 D365 Sales Implementation Costs — r/Dynamics365
  29. 137 Dynamics 365 in Germany and local German regions — Microsoft Learn
  30. 142 Manage configuration and migration data for Dynamics 365 projects — Microsoft Learn
  31. 144 Use server-side synchronization with Sales agent — Microsoft Learn
  32. 146 Contact Deduplication Agent in Dynamics 365 Sales — Microsoft Learn
  33. 149 Key considerations for migrating to Dynamics 365 Sales — Microsoft Learn
  34. 150 How to migrate records from Pipedrive to D365 Sales? — Dynamics 365 Community

Need help running this migration?

FlitStack AI runs Microsoft Dynamics 365 Sales migrations end-to-end.

Fixed-fee pricing, a hands-on migration engineer, full field mapping and validation. The work described in this guide — done for you.