ListMatchGenie
Back to blog
Guide 10 min read

Deduplicating before a Salesforce or HubSpot migration — the playbook

Migrations are when dirty data bites hardest. Duplicates in the source become duplicates in the target, plus new duplicates from merge conflicts. Here's how to dedup properly before cutover, with the order of operations that matters.

Every CRM migration is a data quality moment. You're moving from an old system to a new one, the old system accumulated duplicates over years of neglect, and the migration is your one chance to clean the data before it becomes someone else's problem in the new system.

Most teams know this in principle. Most teams also skip real dedup under migration-deadline pressure and end up with worse data in the new system than they had in the old one — because the migration process itself creates new duplicates on top of the inherited ones.

This is the playbook for doing it right: the order of operations, what to actually clean, what to defer, and how to avoid the specific ways migrations multiply the duplicate problem.

The problem: why migrations multiply duplicates

Three compounding effects:

1. Inherited duplicates

Whatever duplicates existed in the source system get carried into the target. If your Salesforce had 25% duplicates and you migrate 100K records, you now have 25K duplicates in HubSpot (or wherever you're going). Native duplicate rules in the target don't help — they catch new duplicates at save time, not the bulk import that just landed.

2. Migration-created duplicates

Migrations usually combine data from multiple sources (CRM + marketing automation + billing + custom tables). Each source has its own record-keeping conventions. When you concatenate them in the target system, the same real-world customer represented differently in each source becomes 3-5 records in the new system.

3. Schema-translation duplicates

If the source schema and target schema differ, records that were "merged" in source (same person, two contact records linked to one account) may land as separate records in target because the target's relationship model is different. A Salesforce → HubSpot migration famously does this with Contacts attached to Accounts — the Account concept doesn't map cleanly, and relationships fracture.

Net effect: teams routinely discover their post-migration database has 2-3x the duplicate rate of their pre-migration database.

The right order of operations

Most migration plans treat dedup as "a step" — typically late in the project, after everything else is built. That's backwards. Dedup earlier, not later, because:

  • Every migration step that comes after (field mapping, integration setup, reports) is simpler against clean data
  • Dedup-then-migrate is cheaper than migrate-then-dedup because you're moving fewer records
  • User acceptance testing on clean data surfaces real issues, not duplicate-induced noise

Here's the order that works:

Step 1: Profile every source system (1 day)

Before deciding what to dedup, know what you have. Run a profile on each source system to get:

  • Total record count per object
  • Estimated duplicate rate (sample 5K rows, match against itself with a conservative threshold)
  • Field-completion rates (are "email" and "phone" 90% populated or 30%?)
  • Format consistency (are phones formatted consistently or 15 different ways?)
  • Data freshness (when was the last activity on each record?)

This tells you which systems need the most cleanup and which fields are reliable enough to match on.

Step 2: Pick your canonical source per entity (1 day)

If a customer exists in Salesforce, Marketo, and Stripe, one of those is the "truth" for specific fields. Usually:

  • Billing data → Stripe / billing system is canonical
  • Activity / engagement → marketing automation is canonical for recent activity
  • Account / opportunity data → CRM is canonical
  • Contact info → often mixed; pick the most-recently-updated value

Document this explicitly. When dedup finds three records for the same person with conflicting phone numbers, you need a rule for which wins.

Step 3: Standardize in-place (1-2 days)

Before matching across systems, standardize what you can within each system. Low-value but high-leverage cleanups:

  • Phone number format (to E.164 or your chosen canonical format)
  • Email trim and lowercase
  • State/country code standardization
  • Name case normalization (Title Case)

These are one-shot SQL updates or batch API calls. They eliminate a lot of fake duplicates that are really just format differences.

Step 4: Match within each system (half day per system)

Run dedup within each source system first. Salesforce duplicate jobs, or export-match-reimport with a dedicated tool. Goal: at the end of this step, each source system has its records pre-deduplicated.

Don't skip this. Catching Salesforce-internal duplicates before you try to reconcile Salesforce to Marketo is an order of magnitude easier than catching both in one giant match.

Step 5: Cross-system matching (1-2 days)

Now match across systems. Export from each source into a common schema (at minimum: name, email, phone, address). Run probabilistic matching across the combined dataset. Output: a mapping of "this record in System A is the same customer as that record in System B and that record in System C."

Store this mapping somewhere durable — it's the key to the migration.

Step 6: Build survivorship rules (half day)

When three systems have the same customer with different phone numbers, which wins? You decided canonical sources in Step 2; now operationalize that as survivorship rules for each field. Usually per-field:

  • Email → most recently updated
  • Phone → primary canonical source
  • Address → most recently updated, but prefer billing source for billing addresses
  • Account linkage → CRM is truth
  • Activity history → all systems contribute; concatenate

Step 7: Generate the target-system records (varies)

With the cross-system mapping and the survivorship rules, construct the target-system records. Each target record is a merge of its matched source records per the rules.

Step 8: Import, validate, iterate (1-2 weeks)

Import into the target system in waves — start with 1,000 records, validate the result, scale up. Confirm duplicate rules in the target catch any remaining edge cases on new records. Set up ongoing cross-system reconciliation so the migration doesn't regress over the following months.

The specific things that go wrong

Common migration mistakes we see:

Dedup done last, not first

"We'll clean the data after we finish the integrations" — and then there's a deadline and the cleanup gets skipped. Dedup before you build integrations. The integrations are simpler anyway.

Trusting the target system's native rules

"HubSpot will catch duplicates on import." It usually won't, because the import lands as bulk data and HubSpot duplicate rules are weak on bulk. Do dedup externally before import.

Matching only on email

Tempting because email is usually populated and often unique. But personal-email / work-email / old-email splits the same person into three records. Match on a combination of name, email, phone, company — not just one field.

No survivorship rules

When merging duplicates, if you haven't defined which source wins for each field, every merge is a judgment call and you get inconsistent data. Write the rules before merging.

No prevention in the target

Post-migration, if you haven't set up duplicate rules and ongoing hygiene in the target, the duplicates re-accumulate. The migration was your chance to start clean — now start clean properly.

The specific Salesforce → HubSpot pattern

The most common migration we see (and often get called in on):

  • Salesforce has Accounts + Contacts; HubSpot has Companies + Contacts (different model, similar idea)
  • Multiple Contacts per Account in SF become multiple Contacts per Company in HS — except when the mapping breaks and they become standalone Contacts
  • Leads in SF become Contacts in HS; Lead-to-Contact conversion history doesn't carry cleanly
  • Merge history in SF (when you manually merged a duplicate record a year ago) doesn't migrate; the merged-away record may resurface in audit data

Net: a well-architected 500K-record SF → HS migration without explicit dedup produces ~15-25% duplicates in HubSpot. With explicit dedup following the playbook above, it's under 2%.

The specific HubSpot → Salesforce pattern

Same problem, flipped:

  • HubSpot's Company concept maps to SF Account, but HS is more permissive — a Contact can exist without a Company, while SF usually wants an Account
  • HS Lists (especially Smart Lists with dynamic membership) don't have a clean SF equivalent and get flattened to static Campaigns
  • HS lifecycle stages don't map 1:1 to SF Lead/Contact status

The dedup playbook is the same; the field-level translation layer is where the pain is.

Tool picks for migration dedup

For the cross-system matching step specifically, you need a tool that can:

  • Ingest CSVs from multiple sources (Salesforce export, HubSpot export, Marketo export, etc.)
  • Match probabilistically across them
  • Produce a mapping output you can use to drive survivorship
  • Handle international data if your customer base spans locales

ListMatchGenie does exactly this — upload the exports, run matches across them, get the cross-system mapping. For migration projects specifically, the Business tier's 1M-row limit usually handles what you need.

Bottom line

Migrations multiply duplicates if you let them. Done right, with dedup before migration instead of after, the new system is cleaner than the old one was. Done wrong, you've translated your data quality problems into a more expensive platform.

The playbook is straightforward — profile, pick canonical sources, standardize, match within, match across, survive, import, verify. The mistakes are always the same: dedup deferred, too few match fields, no survivorship rules, no post-migration prevention.

If you're in the middle of migration planning and want to test what dedup looks like on your data, ListMatchGenie's free tier handles up to 1,000 rows at no cost. Upload a sample from each source, see the duplicate rate and the cross-system overlap, and you'll have a real number to plan the rest of the migration against.

Topics

salesforce migration deduphubspot migration deduplicationcrm migration data cleanuppre-migration data quality

Let the Genie handle the grunt work.

Free tier is real. No card. No forms. Just upload your first list and see the Genie clean and match it in under a minute.