Custom CRM Data Migration: How to Move Without Losing
83 percent of data migration projects fail, exceed budget, or disrupt operations. The most common reason is not the technology. It is the sequence. Teams wri...

83 percent of data migration projects fail, exceed budget, or disrupt operations. The most common reason is not the technology. It is the sequence. Teams write custom CRM data migration scripts before auditing the source data, run them on production before validating on a test environment, and discover data quality problems after 200,000 records have already been imported.
A migration script that runs in the right order, on clean data, against a tested schema, is one of the most reliable operations in software. A script run wrong is permanent.
About to migrate data into a new custom CRM and not sure your source data is clean enough to import without breaking the schema? Schedule a 30-minute call and we will walk through the pre-migration audit before you write a single line of script. talk to us
Key Takeaways
- Audit before you migrate. Running a migration script on unaudited data imports every data quality problem from the source system into the new CRM at scale.
- Load parent objects before child objects. Accounts before Contacts, Contacts before Deals, Deals before Activities. Loading child records before their parent exists creates orphaned records.
- Test on a copy of production data, not production itself. The first run reveals data quality issues. The second run reveals edge cases. The third run goes live.
- Every migration script must be reversible. A migration without a rollback plan is a gamble with production data that cannot be undone.
- Disable all CRM automation before running the migration. Every active workflow and email trigger will fire on every imported record, sending thousands of automated emails to real customers.
- Validate after every load, not just at the end. Catching an error at the Account load catches it before it propagates to every linked Contact and Deal.
What is a CRM data migration script and what must it do?
A migration script extracts records from a source system, transforms them to match the destination CRM schema, and loads them in the correct sequence. Beyond moving records, it must deduplicate, normalise field values, map source fields to destination fields, load objects in parent-before-child order, validate record counts after each load, and produce an error log for every record that fails.
The script itself is the smallest part of the migration. The preparation work before it and the validation after it determine whether the migration succeeds.
- Extract: pull records from the source system via API, CSV export, or direct database query. Every object type (accounts, contacts, deals, activities) must be extracted completely before transformation begins.
- Transform: deduplicate records, normalise field values, map source fields to destination fields, and convert data types so the destination schema accepts every record without validation errors.
- Load: insert records into the destination CRM in the correct parent-before-child sequence using the destination CRM's REST API or bulk create endpoint. Log every failure without stopping the batch.
- What it must not do: fire CRM automation rules on imported records, send emails or notifications triggered by record creation events, or import records that failed transformation validation.
What must be done before writing a single line of migration script?
Five tasks must be completed before any migration code is written: data audit, field mapping document, data cleaning, schema validation, and disabling all CRM automation. Skipping any one of them produces a category of failure that no script can recover from after the fact.
- Step 1: Data audit. Export every object type from the source CRM and count records, field completion rates, and distinct values in every field used for routing, filtering, or automation. A field with 60 distinct values for Industry is a data quality problem that must be resolved before migration.
- Step 2: Field mapping document. A spreadsheet mapping every source field to its destination field, including source field API name, source field type, destination field API name, destination field type, and any transformation required.
- Step 3: Data cleaning. Deduplicate contacts and accounts in the source. Normalise inconsistent field values. Fill required destination fields that are empty in the source. The goal: zero validation errors when the cleaned data hits the destination schema.
- Step 4: Schema validation. Confirm the destination CRM schema can accept every field in the field mapping document. Required fields, field type constraints, and picklist values must be confirmed before migration starts.
- Step 5: Disable automation. Identify every active workflow, email trigger, lead scoring rule, and notification in the destination CRM. Disable all of them before the first migration run and document what was disabled for re-enablement after validation.
What is the correct object load sequence for a CRM migration?
Always load parent objects before child objects. A child record references its parent by ID. If the parent does not exist when the child is loaded, the relationship cannot be created and the child becomes an orphaned record that cannot be fixed by updating a field.
The load sequence is not a preference. It is a technical requirement enforced by the relational structure of the destination schema.
- Accounts first. No parent dependency. Every other object in a B2B CRM depends on the Account existing before it can be linked correctly.
- Contacts second. Linked to Accounts. Loading Contacts before Accounts means every Contact's Account link is a broken reference.
- Deals/Opportunities third. Linked to Accounts and Contacts. Both must exist before any Deal can be loaded with complete relationship data.
- Activities fourth. Linked to Contacts and Deals. Loading Activities before Deals means every Activity is an orphan with no deal context and no pipeline visibility.
- Tasks fifth. Linked to Contacts and Deals. Loading tasks for deals that do not yet exist in the destination creates unactionable task records.
What must a migration script do during the transform phase?
The transform phase must normalise phone numbers to E.164, convert dates to ISO 8601, map picklist values from source to destination equivalents, handle null values for required destination fields, and maintain a cross-reference table of source IDs to destination IDs for relationship remapping. Underinvesting in the transform phase is the most common cause of relationship failures at load time.
- Phone number normalisation: strip non-numeric characters, apply country code, convert to E.164 (
+1XXXXXXXXXX). Every phone number must match the same format before load or deduplication and search break. - Date format conversion: source CRMs export dates in locale-specific formats (MM/DD/YYYY, Unix timestamp). The destination schema expects ISO 8601 (
YYYY-MM-DD). A format mismatch produces silently incorrect dates without import errors. - Picklist value mapping: source picklist values rarely match destination values exactly. "Software" to "SaaS," "Vice President" to "VP." Unmapped values must be flagged, not silently dropped or loaded as free text that breaks routing.
- Null value handling: fields empty in the source but required in the destination need a default value strategy or a skip rule that flags the record for manual review rather than importing with a wrong default.
- ID remapping: the source CRM's internal IDs will not match the destination CRM's IDs. The migration script must maintain a cross-reference table (source ID to destination ID) and use it to set relationship fields correctly. Without this table every Contact-to-Account and Deal-to-Contact relationship is broken.
How should a migration script handle errors and validation?
Every failed record must be written to an error log with the source record ID, error type, field that caused the error, and source field value. Records should load in batches of 500 to 1,000. A dry-run flag should validate every record's transformations without writing to the destination. Post-load count reconciliation and spot-checks run after each object type is loaded, not only at the end.
- Record-level error logging: every failed record written to a CSV error log with source record ID, error type (required field missing, invalid field type, duplicate key, relationship reference not found), field name, and source value. The error log is the migration team's QA report.
- Batch processing: load records in batches of 500 to 1,000. Prevents a single bad record from stopping the entire load, allows incremental progress monitoring, and prevents API rate limit errors from the destination CRM's REST API.
- Dry run mode: a dry-run flag validates every record's transformations and relationship references without writing to the destination CRM. Treating dry run as optional is how teams discover problems after 200,000 records have already been imported.
- Post-load validation: after each object type is loaded, run a count reconciliation (source count versus destination count), a relationship integrity check (every Contact has a valid Account, every Deal has a valid Contact), and a spot-check of 50 to 100 random records comparing source and destination field values.
At LOW/CODE Agency, we treat dry run as mandatory, not optional. The first production load is never the first run of the script.
What does a rollback plan look like for a CRM data migration?
A rollback plan requires a full database backup taken immediately before the production migration run, a batch ID on every record created by the migration script for targeted deletion, and defined go/no-go criteria before the migration begins. The source CRM must remain accessible for at least 30 days after go-live.
A migration without a rollback plan is not a migration. It is a one-way door into whatever state the script produces.
- Database backup before migration: a full backup or snapshot of the destination CRM taken immediately before the production run. Must be restorable to a point in time before migration began.
- Batch ID tagging: every record created by the migration script tagged with a migration batch ID. If the migration must be rolled back, delete all records with that batch ID rather than manually identifying and removing each one.
- Go/no-go criteria: defined quantitatively before the migration runs. Example: migration passes if 99 percent or more of source records are in the destination, zero records have broken relationship references, and a spot-check of 100 random records shows 100 percent field accuracy. If criteria are not met, rollback triggers.
- Keep the source CRM accessible for 30 days. Some migration steps are not reversible if the source CRM is decommissioned before the destination is validated. Keep read access to the source for at least 30 days after go-live for reference and fallback.
What tools should a CRM migration script use?
Python is the standard language for CRM migration scripts. Pandas handles source extraction and transformation from CSV and Excel. SQLAlchemy connects to relational databases. The requests library handles REST API calls to the destination CRM. A small SQLite or PostgreSQL migration tracking database stores the source-to-destination ID cross-reference, batch IDs, and record status.
- Language:Python is the standard for CRM migration scripts. The ETL library ecosystem (pandas, SQLAlchemy, requests) is the most mature and the error handling patterns are well-established for batch processing.
- Source extraction: if the source CRM has a REST API, extract via API to get clean JSON records. If only CSV export is available, use pandas for extraction and transformation. If the source is a SQL database, use SQLAlchemy or psycopg2 to query directly.
- Destination load: use the destination CRM's REST API with a retry mechanism for HTTP 429 rate limit errors. Use the bulk create endpoint if the CRM supports it: significantly faster than one record per API call at scale.
- Error logging: write the error log to a CSV file during the migration run. One row per failed record with source ID, error type, and field details. Review after each batch before proceeding to the next.
- Migration tracking database: a SQLite or PostgreSQL database tracking the source-to-destination ID cross-reference, migration batch IDs, and the status of each record (pending, loaded, failed). This database is the migration's audit trail and is required for relationship remapping and rollback.
Conclusion
A CRM data migration that goes well is one where the script was written last: after the data was audited, cleaned, and mapped, the schema was validated, and the automation was disabled. The script itself is the smallest part of the work. The preparation is what determines whether the team goes live with clean, trustworthy data or spends the next six months fixing what the migration broke.
Before writing any migration code, run the source data through a field audit and count distinct values for every picklist field. That audit will tell you exactly how much data cleaning is required before the script can be written.
Building a CRM migration that gets the data right the first time
Most CRM data migration problems are not discovered during the migration. They are discovered six weeks after go-live when a pipeline report shows 40 percent of contacts missing their account link, or when finance asks why the invoice data in the new CRM does not match the ERP.
We build AI products for SMBs and mid-market businesses. At LOW/CODE Agency, we design and execute custom CRM data migrations: field mapping, data cleaning, migration scripts with rollback, validation frameworks, and post-load reconciliation, so the team goes live with data they can trust.
- Pre-migration data audit before any code is written: distinct value counts for every picklist field, field completion rates, and duplicate analysis across contacts and accounts in the source system.
- Field mapping document as the migration spec: every source field mapped to its destination equivalent with transformation requirements, type constraints, and null value handling defined before the script is written.
- Parent-before-child load sequence enforced: accounts, contacts, deals, activities, tasks, and attachments loaded in the correct order with relationship validation after each object type completes.
- Dry run mode required before production load: every record's transformations and relationship references validated against the destination schema without writing a single record to production.
- Batch ID tagging and rollback plan before go-live: every imported record tagged for targeted rollback, and go/no-go criteria defined before the production migration run begins.
- Post-load reconciliation report: source versus destination record counts, relationship integrity checks, and 100-record spot-check results delivered before automation is re-enabled and the new CRM goes live.
With 450+ projects delivered for clients including Medtronic, Sotheby's, Zapier, and American Express, we know what a CRM migration looks like when the data is still trustworthy six months after go-live.
If you are ready to build a CRM migration that gets the data right the first time, schedule a call with LOW/CODE Agency and we will start with the source data audit before writing any script.
Last updated on
July 8, 2026
.









