{"id":11052,"date":"2026-10-02T05:12:06","date_gmt":"2026-10-02T05:12:06","guid":{"rendered":"https:\/\/www.coffee.ai\/articles\/migrate-salesforce-contacts-deals"},"modified":"2026-10-02T05:12:06","modified_gmt":"2026-10-02T05:12:06","slug":"migrate-salesforce-contacts-deals","status":"publish","type":"post","link":"https:\/\/www.coffee.ai\/articles\/migrate-salesforce-contacts-deals","title":{"rendered":"How To Migrate Salesforce Contacts And Opportunities"},"content":{"rendered":"<p><em>Written by: Doug Camplejohn, CEO &amp; Co-Founder, Coffee<\/em><\/p>\n<h2 id=\"key-takeaways\">Key Takeaways<\/h2>\n<ul>\n<li>Load Accounts first, then Contacts and Opportunities, to prevent orphaned records and broken AccountId lookups.<\/li>\n<li>Use External ID fields on Accounts, Contacts, and Opportunities to keep parent-child relationships intact during migration.<\/li>\n<li>Treat Opportunity Contact Roles and Opportunity Products as junction objects that require both parent records before loading.<\/li>\n<li>Run validation queries for orphan detection, record counts, and owner assignment as soon as the load finishes.<\/li>\n<li>Coffee keeps migrated Salesforce data accurate, enriched, and usable after the migration completes.<\/li>\n<\/ul>\n<p><a href=\"https:\/\/www.coffee.ai\/pricing?utm_source=ai-growht-agent&amp;utm_term=migrate-salesforce-contacts-deals\" class=\"solid-button\" target=\"_blank\">See Coffee Pricing And Plans<\/a><\/p>\n<h2>Why Import Order Matters<\/h2>\n<p>Correct import order protects Account relationships and reporting accuracy. This sequence applies to org-to-org moves, external CRM imports into Salesforce, and re-platforming projects. RevOps leads, sales ops teams, and Salesforce admins usually run these migrations.<\/p>\n<p>When import order breaks, several related failures appear. <a href=\"https:\/\/hpi.pro\/en\/insights\/salesforce-data-migration-guide\" target=\"_blank\" rel=\"noindex nofollow\">Contacts can load before their parent Accounts exist, which produces lookup failures and orphaned records<\/a>. The same root cause affects Opportunities, which arrive with null <code>AccountId<\/code> values, and it also drives duplicate Accounts when teams match on name instead of ID.<\/p>\n<p><a href=\"https:\/\/pcplusa.com\/insights\/salesforce-data-migration-checklist\" target=\"_blank\" rel=\"noindex nofollow\">Many Salesforce migrations appear successful on load day, then fail weeks later when reps see history on the wrong Account or reports show far fewer Opportunities than the legacy system<\/a>. A disciplined load order prevents those delayed surprises.<\/p>\n<h2>Readiness And Preconditions<\/h2>\n<p>Solid preparation reduces rework and protects relationships during the first load. Before starting, have the following in place:<\/p>\n<ul>\n<li>Source data exported from the origin system<\/li>\n<li>Target org field definitions confirmed, including picklist values that match the source<\/li>\n<li>External ID fields created on Accounts, Contacts, and Opportunities in the target org<\/li>\n<li>User access, profiles, and permission sets configured<\/li>\n<li>Record counts known per object<\/li>\n<\/ul>\n<p>Org-to-org migrations always generate new Salesforce record IDs. <a href=\"https:\/\/resources.rework.com\/guides\/data-migration\/exporting-from-salesforce\" target=\"_blank\" rel=\"noindex nofollow\">Salesforce record IDs are org-specific 18-character alphanumeric strings that do not travel between orgs as durable join keys<\/a>. This ID regeneration breaks relationships when teams rely on old IDs, so External ID fields carry the relationship keys instead.<\/p>\n<h2>How To Migrate Salesforce Contacts And Opportunities: The Full Import Sequence<\/h2>\n<p>This sequence keeps Account relationships intact while you move Contacts and Opportunities.<\/p>\n<ol>\n<li>Export and clean Contacts and Opportunities from the source system, preserving legacy IDs and normalizing field formats.<\/li>\n<li>Load Accounts first so all parent records exist before any dependent object is inserted.<\/li>\n<li>Load Contacts with <code>AccountId<\/code> mapped to the new Account records via External ID matching.<\/li>\n<li>Load Opportunities with <code>AccountId<\/code> mapped to the new Account records via External ID matching.<\/li>\n<li>Rebuild Opportunity Contact Roles after both Contacts and Opportunities are confirmed in the target org.<\/li>\n<li>Rebuild Opportunity Products after both Opportunities and Products or Price Book entries are confirmed in the target org.<\/li>\n<li>Validate record counts, owner assignment, stage and amount integrity, and orphan detection using SOQL queries.<\/li>\n<\/ol>\n<h2>Choosing Your Tool: Data Import Wizard Vs. Data Loader<\/h2>\n<p>Once the load order is clear, the next choice is which tool to run it with. That decision depends on record volume and object type.<\/p>\n<p>The Data Import Wizard is <a href=\"https:\/\/getclientell.com\/salesforce-blogs\/salesforce-data-migration-checklist-2026\" target=\"_blank\" rel=\"noindex nofollow\">browser-based<\/a>, handles simple objects with guided field mapping and <a href=\"https:\/\/getclientell.com\/salesforce-blogs\/salesforce-data-migration-checklist-2026\" target=\"_blank\" rel=\"noindex nofollow\">native duplicate-rule handling<\/a>, and <a href=\"https:\/\/grax.com\/blog\/best-ways-for-salesforce-data-import\" target=\"_blank\" rel=\"noindex nofollow\">caps at 50,000 records per import<\/a>. Data Loader is a <a href=\"https:\/\/resources.rework.com\/guides\/data-migration\/exporting-from-salesforce\" target=\"_blank\" rel=\"noindex nofollow\">desktop application<\/a> that <a href=\"https:\/\/grax.com\/blog\/best-ways-for-salesforce-data-import\" target=\"_blank\" rel=\"noindex nofollow\">supports up to 5,000,000 records per import<\/a> and <a href=\"https:\/\/getclientell.com\/salesforce-blogs\/salesforce-data-migration-checklist-2026\" target=\"_blank\" rel=\"noindex nofollow\">handles all standard and custom objects<\/a>.<\/p>\n<table>\n<thead>\n<tr>\n<th>Feature<\/th>\n<th>Data Import Wizard<\/th>\n<th>Data Loader<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Record limit<\/td>\n<td><a href=\"https:\/\/grax.com\/blog\/best-ways-for-salesforce-data-import\" target=\"_blank\" rel=\"noindex nofollow\">50,000 per import<\/a><\/td>\n<td><a href=\"https:\/\/grax.com\/blog\/best-ways-for-salesforce-data-import\" target=\"_blank\" rel=\"noindex nofollow\">5,000,000 per import<\/a><\/td>\n<\/tr>\n<tr>\n<td>Supported objects<\/td>\n<td><a href=\"https:\/\/getclientell.com\/salesforce-blogs\/salesforce-data-migration-checklist-2026\" target=\"_blank\" rel=\"noindex nofollow\">Accounts, Contacts, Leads, Solutions, Campaign Members, Person Accounts, custom objects<\/a><\/td>\n<td><a href=\"https:\/\/getclientell.com\/salesforce-blogs\/salesforce-data-migration-checklist-2026\" target=\"_blank\" rel=\"noindex nofollow\">All standard and custom objects<\/a><\/td>\n<\/tr>\n<tr>\n<td>Opportunity support<\/td>\n<td><a href=\"https:\/\/getclientell.com\/salesforce-blogs\/salesforce-data-migration-checklist-2026\" target=\"_blank\" rel=\"noindex nofollow\">No<\/a><\/td>\n<td>Yes<\/td>\n<\/tr>\n<tr>\n<td>Interface<\/td>\n<td>Browser-based<\/td>\n<td>Desktop application<\/td>\n<\/tr>\n<tr>\n<td>Duplicate handling<\/td>\n<td><a href=\"https:\/\/getclientell.com\/salesforce-blogs\/salesforce-data-migration-checklist-2026\" target=\"_blank\" rel=\"noindex nofollow\">Native duplicate rules<\/a><\/td>\n<td>Manual configuration required for upsert duplicate handling: the CSV file must contain a column of ID values (an external ID or the Salesforce record ID), and the user must select the matching field in the wizard<\/td>\n<\/tr>\n<tr>\n<td>Export capability<\/td>\n<td><a href=\"https:\/\/getclientell.com\/salesforce-blogs\/salesforce-data-migration-checklist-2026\" target=\"_blank\" rel=\"noindex nofollow\">No<\/a><\/td>\n<td><a href=\"https:\/\/salesforcetutorial.com\/dataloader\" target=\"_blank\" rel=\"noindex nofollow\">Yes<\/a><\/td>\n<\/tr>\n<tr>\n<td>Delete capability<\/td>\n<td><a href=\"https:\/\/getclientell.com\/salesforce-blogs\/salesforce-data-migration-checklist-2026\" target=\"_blank\" rel=\"noindex nofollow\">No<\/a><\/td>\n<td><a href=\"https:\/\/getclientell.com\/salesforce-blogs\/salesforce-data-migration-checklist-2026\" target=\"_blank\" rel=\"noindex nofollow\">Yes (including hard delete)<\/a><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The decision rule stays simple. For under 50,000 records with straightforward, single-object relationships, the Data Import Wizard works well. <a href=\"https:\/\/getclientell.com\/salesforce-blogs\/salesforce-data-migration-checklist-2026\" target=\"_blank\" rel=\"noindex nofollow\">The Data Import Wizard does not support Opportunities, which makes it unsuitable for Opportunity migrations<\/a>. For any load that includes both Contacts and Opportunities, or any volume above 50,000 records, use Data Loader.<\/p>\n<h2>Exporting And Cleaning Contacts And Opportunities<\/h2>\n<p>Clean, consistent source data prevents silent failures and rework. Deduplicate records, normalize field formats, and scan for values that can cause quiet errors before you import.<\/p>\n<p><a href=\"https:\/\/grax.com\/blog\/best-ways-for-salesforce-data-import\" target=\"_blank\" rel=\"noindex nofollow\">Salesforce reads date fields using the org&#8217;s locale settings<\/a>. A file with MM\/DD\/YYYY dates imported into an org configured for DD\/MM\/YYYY will produce mixed-up date values. <a href=\"https:\/\/grax.com\/blog\/best-ways-for-salesforce-data-import\" target=\"_blank\" rel=\"noindex nofollow\">If a Salesforce import includes a picklist value not present in the target org&#8217;s picklist, the record still loads and the field becomes blank<\/a>. That silent failure usually appears later in reports. Opportunity <code>StageName<\/code> values must match the target org&#8217;s picklist exactly.<\/p>\n<p><a href=\"https:\/\/resources.rework.com\/guides\/data-migration\/exporting-from-salesforce\" target=\"_blank\" rel=\"noindex nofollow\">When exporting Contacts, include both <code>AccountId<\/code> and <code>Account.Name<\/code> in each row<\/a>. This approach keeps the parent lookup value and a human-readable parent name available for remapping in the destination org.<\/p>\n<h2>Field Mapping For Contacts And Opportunities<\/h2>\n<p>Correct field mapping keeps core relationships and required fields intact during the load. The next two tables show the minimum mappings you need for Contacts and Opportunities.<\/p>\n<p>AccountId is the relationship field on both objects. It must be populated with the new Account record ID in the target org, not the legacy ID from the source system. Without a valid <code>AccountId<\/code>, both Contacts and Opportunities arrive as orphans.<\/p>\n<table>\n<thead>\n<tr>\n<th>Source Field<\/th>\n<th>Target Salesforce Field<\/th>\n<th>Format Requirement<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>First Name<\/td>\n<td><code>FirstName<\/code><\/td>\n<td>Text<\/td>\n<\/tr>\n<tr>\n<td>Last Name<\/td>\n<td><code>LastName<\/code><\/td>\n<td>Text (required)<\/td>\n<\/tr>\n<tr>\n<td>Email<\/td>\n<td><code>Email<\/code><\/td>\n<td>Valid email format<\/td>\n<\/tr>\n<tr>\n<td>Phone<\/td>\n<td><code>Phone<\/code><\/td>\n<td>Text<\/td>\n<\/tr>\n<tr>\n<td>Title<\/td>\n<td><code>Title<\/code><\/td>\n<td>Text<\/td>\n<\/tr>\n<tr>\n<td>Account ID<\/td>\n<td><code>AccountId<\/code><\/td>\n<td>Must be new Salesforce Account record ID<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<table>\n<thead>\n<tr>\n<th>Source Field<\/th>\n<th>Target Salesforce Field<\/th>\n<th>Format Requirement<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Opportunity Name<\/td>\n<td><code>Name<\/code><\/td>\n<td>Text (required)<\/td>\n<\/tr>\n<tr>\n<td>Close Date<\/td>\n<td><code>CloseDate<\/code><\/td>\n<td>Date format per org locale<\/td>\n<\/tr>\n<tr>\n<td>Stage<\/td>\n<td><code>StageName<\/code><\/td>\n<td>Must match target org picklist values<\/td>\n<\/tr>\n<tr>\n<td>Amount<\/td>\n<td><code>Amount<\/code><\/td>\n<td>Currency<\/td>\n<\/tr>\n<tr>\n<td>Account ID<\/td>\n<td><code>AccountId<\/code><\/td>\n<td>Must be new Salesforce Account record ID<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>Preserving Legacy Salesforce IDs With External ID Fields<\/h2>\n<p>An External ID field is a custom field in Salesforce that stores the source system&#8217;s unique identifier. During migration, populate this field with the legacy record&#8217;s Salesforce ID or other stable key during export. After the target org generates new Salesforce IDs, child records use the External ID to find the correct parent.<\/p>\n<p>The concrete remapping pattern works as follows. A source Contact carries a legacy <code>AccountId<\/code> of <code>001ABC<\/code>. In the target org, that Account receives a new Salesforce ID of <code>001XYZ<\/code>, and its External ID field holds <code>001ABC<\/code>. When you load the Contact, the <code>AccountId<\/code> lookup resolves by matching <code>Contact.Account__r.Legacy_Id__c = 001ABC<\/code> instead of hardcoding the old Salesforce ID. <a href=\"https:\/\/salesforcetrails.com\/guides\/salesforce-data-migration-strategy\" target=\"_blank\" rel=\"noindex nofollow\">This pattern removes the fragile two-pass ID capture and remapping process and makes the load idempotent, so reruns update existing records<\/a>.<\/p>\n<p><a href=\"https:\/\/orgadmin.ai\/blog\/salesforce-data-migration-checklist\" target=\"_blank\" rel=\"noindex nofollow\">External IDs handle three migration jobs: they support idempotent upserts, they resolve relationships by legacy key, and they provide a stable join key for reconciliation between source and destination<\/a>.<\/p>\n<h2>Rebuilding Opportunity Contact Roles And Opportunity Products<\/h2>\n<p>Opportunity Contact Roles and Opportunity Products behave as junction objects that sit between parent records. <a href=\"https:\/\/resources.rework.com\/guides\/data-migration\/exporting-from-salesforce\" target=\"_blank\" rel=\"noindex nofollow\">OpportunityContactRole links Opportunities to Contacts and is often missed during export, which leaves Opportunities in the new CRM without contact relationships<\/a>. Both junction objects require their parent records to exist in the target org before loading.<\/p>\n<p>The load order for these junction objects stays fixed:<\/p>\n<ol>\n<li>Confirm Contacts and Opportunities are fully loaded and validated in the target org.<\/li>\n<li>Load Opportunity Contact Roles, matching each record to its parent Contact and Opportunity via External IDs.<\/li>\n<li>Load Opportunity Products, matching each record to its parent Opportunity and the corresponding Price Book entry.<\/li>\n<\/ol>\n<p><a href=\"https:\/\/salesforcedictionary.com\/terms\/opportunity-contact-role\" target=\"_blank\" rel=\"noindex nofollow\">Each Opportunity Contact Role record holds a <code>ContactId<\/code>, an <code>OpportunityId<\/code>, a <code>Role<\/code> picklist value, and an <code>IsPrimary<\/code> flag, and only one Contact per Opportunity can be marked primary<\/a>. Export both junction objects separately from the source system and remap them using External IDs. <a href=\"https:\/\/salesforcedictionary.com\/terms\/opportunity-contact-role\" target=\"_blank\" rel=\"noindex nofollow\">Without Opportunity Contact Roles, campaign attribution in Salesforce breaks because campaigns sit on Contacts and Leads while pipeline sits on Opportunities, and only Opportunity Contact Roles connect the two<\/a>.<\/p>\n<h2>Post-Migration Validation<\/h2>\n<p>Structured validation confirms that relationships, ownership, and pipeline totals survived the move. Focus on record counts, owner assignment, stage and amount integrity, close-date integrity, and orphan detection.<\/p>\n<p>Start with orphan detection for Contacts. Any result here needs investigation and likely a reload.<\/p>\n<pre><code>SELECT Id, FirstName, LastName FROM Contact WHERE AccountId = null<\/code><\/pre>\n<p>Next, check orphaned Opportunities. A non-empty result set indicates missing or mismatched Account lookups.<\/p>\n<pre><code>SELECT Id, Name FROM Opportunity WHERE AccountId = null<\/code><\/pre>\n<p>Reconcile record counts across core objects. Counts in the target org should match expected totals from the source.<\/p>\n<pre><code>SELECT COUNT() FROM Account WHERE Legacy_Id__c != null SELECT COUNT() FROM Contact SELECT COUNT() FROM Opportunity<\/code><\/pre>\n<p>Review owner assignment to ensure Opportunities are not stuck on an integration user or a single admin.<\/p>\n<pre><code>SELECT OwnerId, COUNT(Id) FROM Opportunity GROUP BY OwnerId<\/code><\/pre>\n<p>Finally, confirm stage distribution and pipeline totals. Compare these results to legacy reports.<\/p>\n<pre><code>SELECT StageName, COUNT(Id), SUM(Amount) FROM Opportunity GROUP BY StageName<\/code><\/pre>\n<p><a href=\"https:\/\/clonepartner.com\/blog\/the-ultimate-crm-data-migration-checklist-a-10-point-plan-for-a-zero-loss-transition\" target=\"_blank\" rel=\"noindex nofollow\">Treat discrepancies in core objects such as Accounts, Contacts, and Opportunities as migration defects that require correction<\/a>. <a href=\"https:\/\/flitstack.ai\/resources\/migration-guides\/salesforce-sales-cloud\" target=\"_blank\" rel=\"noindex nofollow\">Confirm that no Opportunity remains assigned to the integration user by reviewing the <code>OwnerId<\/code> distribution<\/a>. Use Salesforce&#8217;s standard &#8220;Opportunities with Contact Roles&#8221; report type to confirm that Opportunity Contact Roles were rebuilt correctly.<\/p>\n<h2>Common Mistakes And Troubleshooting<\/h2>\n<p>Most migration issues trace back to a short list of avoidable errors. Watch for these patterns and apply the suggested fixes.<\/p>\n<ul>\n<li><strong>Loading Contacts before Accounts:<\/strong> <a href=\"https:\/\/hpi.pro\/en\/insights\/salesforce-data-migration-guide\" target=\"_blank\" rel=\"noindex nofollow\">A Contact requires its Account to exist first<\/a>. Fix: always load Accounts before any dependent object.<\/li>\n<li><strong>Using legacy <code>AccountId<\/code> values:<\/strong> Legacy Salesforce IDs do not work in the target org. Fix: use External ID matching to resolve parent lookups.<\/li>\n<li><strong>Skipping External ID fields:<\/strong> <a href=\"https:\/\/pcplusa.com\/insights\/salesforce-data-migration-checklist\" target=\"_blank\" rel=\"noindex nofollow\">Without External ID fields, every retry becomes a manual reconciliation and every relationship depends on IDs created after the load<\/a>. Fix: create External ID fields on every migrated object before the first load.<\/li>\n<li><strong>Forgetting Opportunity Contact Roles:<\/strong> Many guides omit these records, which breaks reporting and campaign attribution. Fix: export and reload them as a separate pass after Contacts and Opportunities land.<\/li>\n<li><strong>Duplicate Accounts from name-matching:<\/strong> <a href=\"https:\/\/hpi.pro\/en\/insights\/salesforce-data-migration-guide\" target=\"_blank\" rel=\"noindex nofollow\">Names repeat, vary across systems, and often include spacing differences, while a unique External ID from the source system gives clear mapping<\/a>. Fix: match on External ID instead of Account name.<\/li>\n<li><strong>Silent picklist failures:<\/strong> The picklist mismatch described earlier is the most common silent failure, where the record loads, the field blanks, and reporting hides the problem. Fix: audit all picklist values against the target org before loading.<\/li>\n<\/ul>\n<p><a href=\"https:\/\/www.coffee.ai\/pricing?utm_source=ai-growht-agent&amp;utm_term=migrate-salesforce-contacts-deals\" class=\"solid-button\" target=\"_blank\">Keep Your Migrated Data Clean With Coffee<\/a><\/p>\n<h2>Variations And Scaling Considerations<\/h2>\n<p>Large or complex migrations benefit most from a disciplined External ID strategy and careful batching. For org-to-org migrations where every record ID changes, the External ID approach becomes the only reliable path to preserving relationships.<\/p>\n<p>For external CRM imports into Salesforce, field mapping usually presents the main challenge. Source field names, picklist values, and date formats rarely align with Salesforce&#8217;s schema without transformation. For spreadsheet-source migrations, see the <a href=\"https:\/\/coffee.ai\/articles\/migrate-excel-to-salesforce\/?utm_source=ai-growht-agent&amp;utm_term=migrate-salesforce-contacts-deals\" target=\"_blank\">How To Migrate From Excel To Salesforce: Complete Guide<\/a> for a dedicated workflow.<\/p>\n<p><a href=\"https:\/\/getclientell.com\/salesforce-blogs\/salesforce-data-migration-checklist-2026\" target=\"_blank\" rel=\"noindex nofollow\">Data Loader with the Bulk API supports up to 10,000 records per batch<\/a>, and higher volumes push teams toward batch processing and serial mode. Serial mode helps avoid <code>UNABLE_TO_LOCK_ROW<\/code> errors when parallel batches compete for the same parent record. For a broader pre-migration checklist, see the <a href=\"https:\/\/coffee.ai\/articles\/salesforce-migration-best-practices-2026\/?utm_source=ai-growht-agent&amp;utm_term=migrate-salesforce-contacts-deals\" target=\"_blank\">Salesforce Migration Best Practices: 12-Step Checklist<\/a>.<\/p>\n<h2>Frequently Asked Questions<\/h2>\n<h3>How Do I Import Contacts Into Salesforce From CSV?<\/h3>\n<p>Use the Data Import Wizard for smaller jobs under 50,000 records. Go to Setup &gt; Data Import Wizard, select Contacts, upload the CSV, map <code>AccountId<\/code> to the new Account record IDs in the target org, and run the import. For larger volumes, or when loading Contacts alongside Opportunities with relationship dependencies, use Data Loader with an External ID field on Accounts so parent lookups resolve by legacy key instead of Salesforce ID. In every case, load Accounts before Contacts.<\/p>\n<h3>Where Is The Data Import Wizard In Salesforce?<\/h3>\n<p>The Data Import Wizard lives under <a href=\"https:\/\/grax.com\/blog\/best-ways-for-salesforce-data-import\" target=\"_blank\" rel=\"noindex nofollow\">Setup &gt; Quick Find &gt; &#8220;Data Import Wizard&#8221;<\/a>. You can also <a href=\"https:\/\/grax.com\/blog\/best-ways-for-salesforce-data-import\" target=\"_blank\" rel=\"noindex nofollow\">open it directly from a Campaign record to load campaign members<\/a>. It supports Accounts, Contacts, Leads, Solutions, Campaign Members, Person Accounts, and custom objects, but it does not support Opportunities, so any Opportunity load requires Data Loader.<\/p>\n<h3>How Do I Bulk Upload Contacts To Salesforce?<\/h3>\n<p>For bulk uploads above 50,000 records, use Data Loader. Export Contacts from the source with both <code>AccountId<\/code> and <code>Account.Name<\/code> included. Create an External ID field on Accounts in the target org and populate it with the legacy Account identifier during the Account load. Then load Contacts with <code>AccountId<\/code> resolved by matching on the Account External ID field instead of hardcoding the old Salesforce ID. This pattern keeps the load idempotent and removes the need for a manual ID translation spreadsheet.<\/p>\n<h3>How Do I Migrate Opportunities Without Losing Account Relationships?<\/h3>\n<p>Load Accounts first, then load Opportunities with <code>AccountId<\/code> mapped to the new Account record IDs through External ID matching. Create an External ID field on Accounts in the target org, populate it with the source Account&#8217;s legacy identifier, and reference that field when loading Opportunities so the lookup resolves by key instead of Salesforce ID. After loading, validate with <code>SELECT Id, Name FROM Opportunity WHERE AccountId = null<\/code> to find any orphaned Opportunities that failed to resolve their parent lookup.<\/p>\n<h3>What Is A Salesforce External ID Field Mapping?<\/h3>\n<p>A Salesforce External ID mapping connects a field in your CSV to a custom External ID field in Salesforce that stores the source system&#8217;s unique identifier. During migration, you populate this field with the legacy record ID when exporting from the source org. After the target org generates new Salesforce IDs, child records such as Contacts and Opportunities re-link to their parent Accounts by matching on the External ID value. This approach supports idempotent loads, removes manual ID translation, and provides a stable join key for post-migration reconciliation.<\/p>\n<h2>Conclusion<\/h2>\n<p>Migrating Salesforce Contacts and Opportunities is a dependency graph problem that rewards a clear sequence and careful validation. Load in the correct order, preserve legacy keys with External ID fields, and confirm every relationship with SOQL orphan detection queries before you call the migration complete.<\/p>\n<p><a href=\"https:\/\/www.coffee.ai\/pricing?utm_source=ai-growht-agent&amp;utm_term=migrate-salesforce-contacts-deals\" class=\"solid-button\" target=\"_blank\">Explore How Coffee Supports Your Salesforce Migration<\/a><\/p>\n<section data-read-next=\"true\">\n<h2>Read Next<\/h2>\n<ul>\n<li><a href=\"https:\/\/coffee.ai\/articles\/migrate-excel-to-salesforce\/\" target=\"_blank\">How to Migrate from Excel to Salesforce: Complete Guide<\/a><\/li>\n<li><a href=\"https:\/\/coffee.ai\/articles\/migrate-salesforce-without-losing-data\/\" target=\"_blank\">How to Migrate Salesforce Without Losing Data<\/a><\/li>\n<li><a href=\"https:\/\/coffee.ai\/articles\/salesforce-migration-automation-2026\/\" target=\"_blank\">Salesforce Migration Automation: Tools &amp; Best Practices<\/a><\/li>\n<li><a href=\"https:\/\/coffee.ai\/articles\/migrate-from-salesforce-crm\/\" target=\"_blank\">How to Migrate from Salesforce to Another CRM<\/a><\/li>\n<li><a href=\"https:\/\/coffee.ai\/articles\/salesforce-migration-problems-2026\/\" target=\"_blank\">Salesforce Migration Problems: A 7-Step Prevention Playbook<\/a><\/li>\n<\/ul>\n<\/section>\n","protected":false},"excerpt":{"rendered":"<p>Learn how to migrate Salesforce Contacts and Opportunities without breaking Account relationships. Follow Coffee&#8217;s proven step-by-step guide.<\/p>\n","protected":false},"author":11,"featured_media":11051,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-11052","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.coffee.ai\/articles\/wp-json\/wp\/v2\/posts\/11052","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.coffee.ai\/articles\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.coffee.ai\/articles\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/www.coffee.ai\/articles\/wp-json\/wp\/v2\/comments?post=11052"}],"version-history":[{"count":0,"href":"https:\/\/www.coffee.ai\/articles\/wp-json\/wp\/v2\/posts\/11052\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.coffee.ai\/articles\/wp-json\/wp\/v2\/media\/11051"}],"wp:attachment":[{"href":"https:\/\/www.coffee.ai\/articles\/wp-json\/wp\/v2\/media?parent=11052"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.coffee.ai\/articles\/wp-json\/wp\/v2\/categories?post=11052"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.coffee.ai\/articles\/wp-json\/wp\/v2\/tags?post=11052"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}