Business & Revenue OpsFree
Data Migration Field Mapping Template
Both field exports in, a target contract and a source disposition out, and every rule carrying what a bad value actually does at load.
River reads both systems' field exports and produces two passes rather than one. The first is keyed on the target: one row per destination field, with the source that feeds it, the transformation, and the rule. The second is keyed on the source: one row per column in the export, carrying a disposition of mapped, transformed, merged, produced by the target, or dropped with a named signer. Every row also records what a non-conforming value does at load, which is a different question from what the rule says.
The published mapping templates are good, and they share one design decision that costs them this. Every one is organised as a row per target field, worked down the target inventory, on the reasoning that the target is the contract you are filling. A sheet with no row for a source field cannot enumerate the source fields you dropped. So the argument three weeks after cutover is about a column that was never on the page, and the inventory each row rests on is a field dictionary per system.
Built for the operations lead or implementation consultant who owns the load, and for the person who has to answer for a missing column three weeks afterwards. Reach for it before the first test load, when both field exports exist and the decisions do not. Knowing what shape the source is in before you map it is a CRM audit, and proving the loaded records match the export afterwards is a record-level reconciliation. Sizing the freeze window the load has to fit inside is a system migration plan.
A bad value does one of three things, not one
Take the row every mapping sheet has, a legacy status code into a dropdown. HubSpot's own error catalogue says what happens when a value is not one of the defined options: the affected records were still imported, and the property does not contain a value. Not a rejected row, not a failed load. A complete import with an empty cell. The same outcome is documented for an owner who matches no user, a date in the wrong format, and any value failing a validation rule.
A third outcome is quieter still. HubSpot documents that the Company domain name property accepts values only to the top-level domain, and that anything after it will be automatically removed on import. The value loads, changed, with no error raised. Which means a migration validated on record counts passes cleanly while carrying tens of thousands of empty cells and a set of silently rewritten values. The count is the one number this failure mode cannot touch.
Which of the three you get is a property of the target, not the rule. PostgreSQL raises an error on a string longer than the column allows, and then truncates the identical value without raising an error if the loader casts it explicitly. Same value, same column, opposite outcomes. HubSpot rejects the row outright for a required property, an invalid email, or a deal stage that does not exist. So the mapping row needs the failure mode written next to the rule.
How it works
Hand over both exports
The source system's field list and the target's, plus a sample of the real data.
Map to the target
Every destination field gets a row, a source, a transformation and the rule that governs it.
Run the source pass
Every source column gets a disposition, and the ones with no target row get flagged.
Add the failure mode
Each rule gets what a bad value does at load, with the row count behind it.
What you get
- One row per target field with its source, transformation and the rule behind it
- One row per source column, so a field with no target row cannot hide
- The failure mode on every rule: rejects the row, empties the field, or rewrites it
- Picklist value conflicts counted, including case variants and the single-occurrence long tail
- The deliberately dropped list, each row naming the person who signed the decision
- Row counts per field, so the cost of each conflict is a number before you load
Common questions
Why does the mapping need a second pass keyed on the source?
Because a sheet organised by target field has no row for a source field that maps nowhere. Work down the target inventory and you finish with a complete load contract and an unenumerated set of orphaned columns. Those orphans are exactly what the post-migration argument is about, so they get their own pass and their own sign-off.
Do picklist conflicts break the import?
Usually the opposite, which is what makes them dangerous. HubSpot documents that a value matching no defined option still imports the record and leaves the property empty. The load reports success, the record count reconciles, and a field is blank on every affected row. River counts the affected rows per field before you load, so the number is a decision rather than a discovery.
What counts as a picklist conflict beyond an unmapped value?
Case and whitespace variants that read as identical and load as distinct. Two source values collapsing onto one target option irreversibly. A label matching more than one defined option, and a free-text column feeding a controlled list where most values appear once. River separates them, because the first three are fixable in the file and the last is a scope decision.
What does the dropped-field document actually contain?
One row per source column with no target row, carrying how many records populate it, what it was used for, the name of the person who agreed to drop it, and the date. On the worked example five columns qualify, and one of them decides which contract governs a hire, on every single record.
Does it work for a warehouse target, not just a CRM?
Yes, and the failure modes differ in useful ways. PostgreSQL errors on an over-length string and truncates the same value silently when the loader casts it, so the same mapping row behaves differently depending on how the pipeline writes. River reads the target's own type definitions and records the behaviour rather than assuming the strict case.
How do I prove the load worked afterwards?
Not with a record count, which this failure mode leaves untouched. The check is per field: how many rows carry a value on each side, against the count River predicted before the load. A field arriving emptier than forecast is a mapping defect. Where two systems now both hold the data, a reconciliation between them settles which is authoritative.
Data Migration Field Mapping Template
Fill in the form and your workspace opens with the work already underway.