Salesforce Data Migration: Step-by-Step

Salesforce Data Migration: Step-by-Step

Run a Salesforce data migration without losing or duplicating records. Map leads, contacts, accounts, test a batch, backfill, then keep the source synced.

No credit card required

Free 100k syncs every month

Most Salesforce data migration guides treat the load as the finish line. You extract from the old system, transform it somewhere, drop it into Salesforce, and the project is "done." Then the old system keeps running for another three weeks while your team learns the new one, and the two datasets quietly drift apart again. The migration was never the hard part. Staying aligned afterward is.

This guide covers the practical path: what a Salesforce data migration actually moves, how to map records to Salesforce objects without creating duplicates, and how to run a test batch before the full load. For the generic six-step process that applies to any tool pair, see our step-by-step data migration process guide. Here we go deep on the parts specific to Salesforce.

What a Salesforce data migration moves: objects, records, and relationships

Salesforce does not store everything in one flat table. It stores records in objects, and the objects relate to each other. The migration has to preserve both the records and the links between them, or you end up with orphaned data that looks complete until someone tries to use it.

The three objects that matter for almost every migration:

  • Leads — people who are not yet qualified. A standalone record with no required parent.

  • Contacts — people tied to an organization. A Contact belongs to an Account through a lookup relationship.

  • Accounts — the organizations themselves. Contacts and Opportunities point back to an Account.

The relationship is the trap. If you load 5,000 Contacts before their Accounts exist, the Account lookup on each Contact comes back empty, and you spend a day re-linking records by hand. The fix is ordering: migrate Accounts first, then Contacts, then Opportunities and anything else that references them. Same rule for any custom object that has a lookup to another.

Decide upfront whether each person in your source is a Lead or a Contact. Some teams migrate everyone as a Lead and convert later. Others split on a status field. Either works, but pick one before you map fields, because the target object changes which Salesforce fields are available.

How to prepare your data before a Salesforce data migration

The 30 minutes you spend cleaning the source saves a week of cleanup inside Salesforce. Every duplicate, malformed email, and test row you load becomes a record someone has to find and fix later, scattered across objects.

Work through four checks on the source data:

  • Deduplicate. Sort by email and remove repeated people. Sort organizations by domain and merge the duplicates. Salesforce has its own duplicate rules, but cleaning at the source is faster than untangling it after the load.

  • Standardize formats. Pick one format per field and fix every cell that does not match. Emails lowercase and trimmed. Phone numbers in E.164. Dates in ISO 8601. Salesforce rejects values that do not fit a field's type, and a rejected row is a lost record if your tool drops failures silently.

  • Pick a matching key per object. Email for Contacts and Leads, domain or an external ID for Accounts. This is the field that prevents duplicates on every run. Without one, a re-run creates a second copy of every record.

  • Flag the custom fields. Note any source field that has no obvious home in a standard Salesforce object. Those become custom fields, and you need to create them before the load.

One detail people miss: Salesforce field-level security and validation rules will reject records that a CSV import would happily accept. A required custom field with no value, a picklist value that is not in the allowed set, a text field over its character limit. Check your org's validation rules against your source data before you run anything, not after the full load fails halfway through.

Field mapping for migrating data to Salesforce: leads, contacts, and accounts

Field mapping is where a Salesforce migration succeeds or breaks. Each source field maps to a specific Salesforce field on a specific object, identified by its API name (the one ending in __c for custom fields). Map a phone number to a text field and it loads fine but breaks every phone-based workflow downstream.

Build a mapping table per object before you open any migration tool:

Source field

Salesforce object.field

Type

Notes

Company

Account.Name

Text

Load Accounts first

Website domain

Account.Website

URL

Matching key for Accounts

Full name

Contact.FirstName + LastName

Text

Split on first space

Email

Contact.Email

Email

Matching key for Contacts

Phone

Contact.Phone

Phone

Convert to E.164

Account link

Contact.AccountId

Lookup

Resolve by Account domain

Status

Lead.Status

Picklist

Remap to org's allowed values

Plan tier

Account.Plan_Tier__c

Picklist

Custom field, create first

Signup date

Contact.CreatedDate

Date

ISO 8601 conversion

Three Salesforce-specific things break more than anything else:

Picklist values that do not match. Your source says "warm lead." The Salesforce Lead Status picklist has Open, Working, Qualified, Unqualified. Salesforce rejects any value not in the allowed set. Build a value-to-value remap for every picklist column, or those rows fail.

Relationship lookups by ID. A Contact's AccountId is a Salesforce record ID, not a company name. Your source does not know that ID. You resolve the lookup on a shared key instead: match the Contact's company domain to an Account that already exists, and let the tool fill in the ID. This only works if Accounts were loaded first.

Missing custom fields. Your source has fields like plan tier or renewal date that no standard Salesforce object holds. Create the custom fields in Salesforce Setup before the migration runs, or use a data migration tool that creates the missing fields with the right type automatically.

Running the Salesforce data migration: test batch first, then full load

Never run a Salesforce data migration straight onto the full dataset. A test batch of 50 records catches the mapping errors that would otherwise repeat across every record in your org.

Pick the test records deliberately, not at random. Include:

  • Records with every custom field populated

  • People with no email or no company

  • A Contact whose Account does not exist yet, to test your lookup resolution

  • Names with accents, apostrophes, or non-Latin characters

  • The oldest and newest records, to catch date-format edge cases

Run the batch, then open Salesforce and inspect 10 records field by field. Check the fields you did not think about, because those are the ones that break. Look specifically for empty Account lookups, picklist values that fell back to a default, and dates showing as 1970.

Once the test passes, run the full load in object order:

  1. Load Accounts. Use Update or Create on the domain or external ID key. Every organization becomes an Account before any Contact references it.

  2. Load Contacts and Leads. Use Update or Create on email. The Account lookup resolves against the Accounts you just loaded.

  3. Load related records. Opportunities and custom objects that point back to Accounts or Contacts.

  4. Review failed records. A record that hit a validation rule or a rate limit should surface for review, not vanish. Fix the root cause and reprocess.

After the load, validate before you trust it. Compare record counts per object against the source — Accounts, Contacts, Leads should each match within a percent or two. Then spot-check 20 records across objects, confirming the Account lookups actually resolved. A migration that reports "success" but left 2,000 Contacts unlinked is worse than one that errored out loudly.

Among the Salesforce data migration best practices worth keeping: migrate in object order, always test a batch first, and never run the full load against a production org you have not backed up. A sandbox dry run is cheap insurance.

After migrating data to Salesforce, keep the source system in sync

Here is the part the ETL crowd structurally cannot offer. When a migration is a one-time extract-transform-load job, it ends the moment records land in Salesforce, and the source keeps changing without it. A week later your data has drifted, and a year later you are scoping the same Salesforce data transfer all over again.

There is a better default: treat the migration as a sync with a starting point. The backfill that moved your historical records was step one. Now leave the same connection running on a schedule. Every 15 minutes, only the records that changed in the source flow into Salesforce. Your team keeps using the old system while it winds down, and Salesforce stays current the whole time.

With Oneprofile, migrating data to Salesforce and keeping it synced are the same configuration:

  • Connect your source and Salesforce with OAuth or API keys.

  • Map fields to Leads, Contacts, and Accounts in the visual mapper. Missing custom fields are created in Salesforce with the right type.

  • Choose Update or Create on your matching key, so the run updates matches instead of duplicating them.

  • Run the backfill, then set a schedule. Property-level change tracking means only the fields that actually changed get written, which keeps you inside Salesforce API limits and avoids overwriting fields another tool owns.

  • Watch the run. Records that fail are flagged for review and retry, never dropped silently.

When your team has fully moved off the old system, you stop the schedule. No second tool, no re-mapping, no re-migration. The Salesforce data migration becomes ongoing sync by changing one setting.

Ready to get started?

No credit card required

Free 100k syncs every month

Ready to get started?

No credit card required

Free 100k syncs every month

Ready to get started?

No credit card required

Free 100k syncs every month

How long does a Salesforce data migration take?

How do I migrate data to Salesforce without creating duplicate records?

What is the most common Salesforce data migration mistake?

Do I need a data warehouse for a Salesforce migration?

Can I keep my old system after migrating data to Salesforce?

What Salesforce objects can I migrate records into?