Migrations & tech debt
Platform moves, automation consolidation, and paying down the accretion that makes every change slower: how to migrate the contract, not just the rows.
Related
The worst migration I ever inherited had 282 active automations firing on the Opportunity object. Nobody could tell me what any single one did, because the org had eleven admins over six years and each one added a workflow rule rather than touch the one already there. Saving an opportunity took nine seconds and sometimes threw a CPU-limit error that no rep could parse. That is tech debt in its terminal form: not a bug, but a fog where every change risks breaking something invisible, so nobody changes anything, so the fog thickens. We got it down to 82 automations over a quarter, and the first hard part was not deleting them. It was proving what each one still did.
Migrations and tech debt are the same problem seen at two time scales. A platform move (HubSpot to Salesforce, SBQQ to a new CPQ, a home-grown routing script to LeanData) is tech debt paid down all at once under a deadline. Day-to-day debt is the same accretion paid down never, until it forces a migration. The teams that stay fast treat both as the same discipline: migrate the contract first, the rows second, and never carry logic across you cannot explain.
Migrate the contract, not the rows
The instinct on a platform move is to start with the data: export everything, map the columns, load it in. That is backwards. The rows are the easy part. The hard part is the data contract, the set of agreements about what each object means, what grain each field lives at, and who writes it. Land rows against an undefined contract and you recreate the mess you were trying to leave, at a new vendor’s monthly rate.
So the order is: define the target object model, define the field contract (grain, writer, definition), define the matching keys, and only then move data. If half your source accounts store the domain as acme.com and half as a full URL, normalize before the load, because the match key is the spine everything else hangs on.
Consolidating automation is archaeology before surgery
The 282-automation org taught me the sequence. You cannot safely delete what you cannot explain, so the first pass is pure archaeology: catalog every automation, its trigger, its actions, and the last time it actually fired. Debug logs and the metadata itself tell you the last part. Anything that has not fired in a year is a candidate, but a candidate is not a verdict, because some logic only fires on rare events (a renewal, a specific stage jump).
Then you group by object and by intent. Ten workflow rules that each stamp one field on Opportunity save become one before-save flow. Before-save flows also run an order of magnitude faster than the old workflow-rule-plus-process-builder stack, which is what killed the nine-second save.
// Consolidation smell test: how many separate automations touch one object?
// High counts here are where CPU limits and unexplainable behavior live.
SELECT TableEnumOrId, COUNT(Id) automations
FROM WorkflowRule
GROUP BY TableEnumOrId
ORDER BY COUNT(Id) DESC
View as table
| Stage | Value |
|---|---|
| Before: workflow rules | 141 automations |
| Before: process builders | 88 automations |
| Before: legacy flows | 53 automations |
| After: consolidated flows | 82 automations |
Platform moves: what actually breaks
| What teams plan for | What actually breaks | |
|---|---|---|
| Object mapping | Contacts to contacts, one to one | Source has no Lead object, target does; pre-qualification stage has no home |
| Automation | Rebuild the same rules | Half the source rules were dead; nobody knows which half |
| History | Migrate open records | Reporting needs closed history too, at a grain the source never stored |
| Identity | Match on email | Free-mail and shared inboxes collapse distinct people into one |
| Cutover | One weekend | Dual-run period where both systems are writing and drifting |
- 1
1. Define the target contract first
Object model, field grain, one writer per field, match keys. This is 60 to 70% of the real work and none of it is loading rows.
- 2
2. Profile the source before mapping
Duplicate rate, null rates, free-text sprawl, dead automations. You cannot map what you have not measured.
- 3
3. Normalize match keys at the source
Strip domains to the bare host, dedup, resolve identity. A broken key poisons every downstream match.
- 4
4. Rebuild automation on the new model, do not port it
Recreate intent, not implementation. Dead source rules stay dead; live ones become consolidated flows.
- 5
5. Dry-run into a sandbox and reconcile counts
Load into a full sandbox, reconcile every object count and ARR total against the source before touching production.
- 6
6. Dual-run, then cut over on a reconciled number
Run both systems briefly, freeze writes on the source, cut over only when the target reconciles to the source exactly.
Paying debt down before it forces your hand
The debt you pay on a schedule is cheaper than the debt that forces a migration. A standing quarterly hygiene pass keeps the fog from thickening: retire unused fields, deactivate automations that stopped firing, collapse overlapping validation rules, and delete reports nobody opens. None of it is glamorous and all of it compounds, in the good direction this time.
A migration is never really about the new platform, and tech debt is never really about the old code. Both are about whether anyone can still explain what the system does. Migrate the contract first, consolidate by intent, deactivate before you delete, and keep the export. Do that and the platform underneath becomes a choice you make on purpose, instead of a hostage situation you inherited.
Keep reading
All guides →Object & data model
How the standard objects, record types, and custom fields fit together, plus the grain rules and relationship choices that decide whether reporting ever ties out.
ArchitectCPQ & quote-to-cash
How quotes, price books, approvals, and billing connect into one revenue chain, plus the config choices that decide whether a signed deal actually invoices correctly.
ArchitectAutomation architecture
How flows, triggers, and validation rules coexist without fighting, plus the order-of-execution and consolidation rules that keep automation from eating itself.