← Migrations
How we run them

Six disciplines a migration has to satisfy at once

A migration fails in more than one direction. It can be technically clean and still lose the quarter, or delivered on time and quietly illegal. These are the lenses the work gets held against, drawn from the 15 moves we can name.

Product management · systems analysis

Discovery: what is actually running, not what people think is running

Ask around and every answer you get will be honest and incomplete. The person who built the nurture remembers the nurture. Ops remembers what broke. Nobody remembers the operational program a contractor stood up before the rebrand before last, still firing nightly, still stamping a field that a CRM assignment rule reads. Recall gets you a hypothesis list. Treat it as one, then go and find evidence.

Every platform will tell you what is alive if you ask it properly. Last-run and last-activity dates on every operational program, automation rule and workflow. Sends by asset over a trailing window. Form submissions counted by month, never lifetime, because lifetime totals flatter assets that died years ago. Then the part most teams skip: for each field, how many records hold a non-null value, and when it was last written. A field existing in the schema tells you nothing — plenty were built for one campaign in a forgotten quarter and still clutter every picklist. Those counts are the field-use audit everything downstream relies on.

Look outside the platform as well, because the export will not. On a Segment to Marketo consolidation our consultants delivered for an aviation and robotics business, the site pages themselves had to be updated to carry the tracking script, and the reporting the business actually looked at sat in Tableau. Neither shows up in an audit that stops at the platform's own admin screens.

What the inventory carries against each object:

  • An owner. Not a team — a person who would notice if it stopped.
  • The last time it did anything: ran, sent, took a submission, wrote a value.
  • Dependencies in both directions. The tracking script on pages built outside the CMS. A webhook. A scheduled extract reading the platform's tables straight into a BI tool. A nightly file drop from a system marketing has never heard of, which keeps arriving after cutover whether or not anything is listening.
  • A disposition — move, rebuild, archive, kill — with the name of whoever agreed it.
  • Whether anyone can describe the intended behaviour without opening it. Often the answer is no. Write that down; it is a finding in itself.

The argument worth having early: most of a legacy instance should not move. Lifting everything and tidying up afterwards is the most expensive decision on the table: the tidying never happens, and you have paid to rebuild rubbish that now looks like a deliberate choice. Nothing moves unless someone justifies it. An asset with no named owner does not move, and "we might need it" is not an owner. What stays behind gets exported, kept readable, and put on the retention register with an owner and a date it goes; an archive with no retention owner is a liability with a filename.

We write acceptance criteria before anyone logs into the destination. "The nurture is migrated" is not one. A criterion says that a person submitting the demo form with a given country value enters the stream, receives the second email on the same delay as production, is checked against the same suppression list, and the sync writes the same value to the same CRM field. Across the migrations we have run it has done double duty: it becomes the go/no-go checklist at cutover, thresholds attached, and it decides sequencing — which instance goes first, which workspace and person partition each acquired organisation lands in, which sending subdomain carries its mail.

The work itself is dull, and anyone who says otherwise is selling a tool. Someone reads every flow step by hand. In a HubSpot to Odoo build our consultants delivered for an authenticator product company, that meant transcribing operational program logic held in regular expressions and testing each condition on its own, in a platform the team had to learn from scratch first. Nothing does this for you.

Use the political window while it is open. Propose switching off the regional newsletter in a normal quarter and you have started an argument with whoever launched it. During a migration the burden of proof flips — everything must earn its passage — and programs that survived several budget cycles die quietly in a spreadsheet review. That window shuts on the go-live date and it does not reopen.

Project and programme management

Sequencing: the order that keeps you off the critical path

Schedule risk on a migration is mostly waiting, and mostly in other people's queues. Someone has to request a sending subdomain from whoever owns DNS, and in most organisations that is not marketing but a ticket queue with a service level and no interest in your go-live date. The DKIM record has to be published and propagate before a single send leaves the new instance. A CRM sandbox refresh needs a window from a CRM team working to its own release calendar. None of it is hard; all of it has a lead time you do not control, and any of it can quietly become the thing everything else waits on while the team is busy documenting smart campaigns.

So we put these in during week one, before discovery finishes and before anyone has signed off scope:

  • Sending subdomain and DNS requests, with the exact record values pasted into the ticket so it does not come back asking what you meant
  • DKIM keys generated, published, verified, then left alone
  • The tracking domain requested in the same ticket — a separate record from the sending subdomain, doing a different job, and the one that gets forgotten
  • A dated CRM sandbox refresh commitment. Not a verbal "sure, whenever"
  • The consent review opened, because the field map cannot be finished without it
  • Security review and vendor questionnaires, opened the week the platform is chosen
  • Procurement — specifically, who signs

Then the build order. Instance architecture comes before everything else: workspaces, person partitions, sending subdomains, and the sync user's profile with its field-level permissions. That profile is an architecture decision, not an admin task: it fixes which fields the integration can ever write, and widening it later means retesting every operational program that uses them. Decide a person partition boundary late and you are not making a configuration change, you are running a data migration inside your migration. The field map comes after the architecture and after the consent review, in that order: the review decides which populations are mailable and which evidence fields must exist to hold the proof, and a map drawn before it is drawn twice. Operational programs come next: lifecycle, scoring, normalisation, routing, suppression, unsubscribe handling. Assets go last, and there should be fewer of them than the brief assumes.

Consolidation adds a question people avoid. Which instance goes first. Take the one with the most reusable logic — the cleanest scoring model, the operational programs you would move rather than rebuild — not the business unit with the loudest sponsor. When our consultants folded several Pardot instances into one Marketo instance for a web-based solution provider in 2020, after a run of acquisitions, whichever went first set the pattern the rest inherited: a workspace and person partition per acquired organisation, and a sending subdomain each. Start with the loudest business unit and the architecture ends up shaped around their edge cases, which you spend the rest of the programme apologising for.

Freeze windows go into the plan before the plan is agreed. Campaign calendars, quarter end, the annual event. A go-live in the last fortnight of a quarter is worth arguing out while arguing is still cheap: it can be done, but the people whose decisions you need are chasing their own numbers, and rollback stops being a technical conversation.

Run a parallel period rather than a hard cutover. New sends leave the new instance; the old one stays up and keeps taking form posts until a full campaign cycle has been through it. The calendar cost goes in the plan: two instances under change control for the whole period, a daily import of whatever the old instance captures into the single suppression list, and a team that has to check which system a record lives in before answering a question about it. QA and cutover set what the parallel run has to prove; release engineering owns the repointing register and the date the old instance stops taking posts.

The plan will change anyway. A dependency map earns its keep on the afternoon DNS tells you the sending subdomain needs another fortnight and you have to work out, before the end of the day, what else moved and who has to be told.

Platform and release engineering

Release engineering: version control, environments and a rollback you have tested

Marketing teams edit production directly and have stopped noticing they do it. Someone opens the email template, changes a token, saves. Live. No diff, no reviewer, nothing to go back to but somebody's memory of the old version.

Anything that is text — email templates, landing page HTML, the tracking script, the JavaScript that stuffs hidden fields before submit — belongs in a repository; the platform is a deploy target, not the source of truth. In an Eloqua to Marketo migration our consultants delivered for an aviation agency in September and October 2019, the site's data-collection layer was its own build: rebuilt in AngularJS and Handlebars, kept in GitHub for exactly this reason. When a field stopped populating, "what changed, and who changed it" had an answer instead of a shrug.

Environment parity is where this gets honest. A MAP sandbox drifts from production unless someone is funded to keep it in step, and that funding rarely survives the business case. So build the parity you can get: a separate workspace, a seed partition holding only the seed records QA maintains, a duplicate form set posting to a staging endpoint. Then write down plainly what you cannot test at all — a smart campaign triggering on a visit to a real page by a real person is only ever exercised in production, so plan its blast radius rather than pretend otherwise.

Deploy tracking through the tag manager, not through a release: a container version can be reverted by one person in a minute. Then repoint forms in batches. Be precise here: this is the state that gets misread as a fault later. Through the parallel period both handlers are live on purpose. A first batch of low-volume forms that still submit every day posts to the new endpoint; the rest keep posting to the old handler, which still writes into the old instance. Contact-us is a good first candidate; a rarely-submitted gated report is a terrible one, because silence from it proves nothing. Every form sits on a repointing register with its current post endpoint and the date it moves. The old handler is switched off on the last day of the parallel period, the same day the old instance stops taking posts — a date that goes into the plan before the first form moves. Before it, dual posting is the design. After it, a form still posting to the old endpoint is a live defect. The register tells the two apart.

One line is worth holding: if you cannot roll back, you are not ready to cut over, and we will not agree a cutover date against a rollback that exists only as a paragraph in a project plan. A tested rollback needs:

  • The steps in order, each with an owner named by role. Who repoints the CNAME, who reverts the container version, who puts the form handler back.
  • Exports of whatever you are about to overwrite — the field map, each form's post endpoint, the current container version — taken the day before, the only copy that matches what is live.
  • A trigger agreed in writing. "Submissions across the top forms sit below last week's floor for two hours" is a trigger. "It feels wrong" is not. It sits in the go/no-go document, not one of its own.
  • Honest timings. DNS TTLs and DKIM propagation set the floor on how fast a repoint can be undone.
  • One rehearsal, run by whoever will run it on the day. In the MAP sandbox it cannot prove the platform behaves identically — the sandbox has drifted, and the write-up should say so. It proves the half that actually fails: the order, the access rights in the right hands, and that whoever holds the runbook has done it once before doing it under pressure. The container revert is the one step you can rehearse for real, in the tag manager.

Observability is the first thing cut when the plan slips. A daily submission count per form with an alert on zero costs almost nothing to build; the alternative is a salesperson asking why their inbox has gone quiet. Build it before cutover and wire it into the hypercare rota, so it reaches whoever is on duty rather than a mailbox.

Marketing leadership and revenue operations

Revenue continuity: what leadership sees while the platform moves

Activity history in the destination starts at cutover. What came before arrives flattened — an original source field, a lifecycle stamp, a created date that no longer lines up with first touch. Any report or scoring rule with a lookback window will behave oddly the first time it runs. Trailing-window smart lists come back thin. Decay rules built on inactivity fire on people who were engaged right up until the old system stopped feeding them, and a cohort view shows a cliff that is only the migration. None of that is a defect. On a dashboard it looks exactly like one.

So we tell the reporting stakeholders first. The demand gen lead, whoever pulls the source-of-record number for finance, before the first report lands, with the charts that will look wrong named in advance. Someone who was warned asks a question. Someone who was not escalates, and from that point you are defending the project rather than running it.

Technical failure is not the expensive risk, whatever the risk register says. It is loud, it announces itself, and it gets fixed the same day. The expensive case is the quiet one. A routing rule that assigns to a queue that is not being worked: every technical measure says the leads arrived, and not one of them has been opened. A set of site pages that never received the updated tracking script, so a whole section of the site drops out of source data while every report still runs. Both run unnoticed until somebody builds a board deck and the shape of the funnel is wrong.

Consolidation sharpens it. Several instances folded into one, a person partition per acquired organisation, and the first question from leadership is rarely technical — it is whose definition of a lead the merged number now uses. Answer that before the merged number appears in a deck.

Lead flow to sales is what you defend hardest, above nurture, above the asset library, above reporting. Sales will forgive a drip that goes quiet for a fortnight. They will not forgive leads not arriving, and they will remind you of it long after it has been fixed.

  • One named owner on each side of the handoff, marketing ops and sales ops, reachable through the cutover weekend.
  • Routing and assignment tested with real records a rep will actually open. A lead called Test Test routes perfectly and tells you nothing about how a real record behaves.
  • Scoring thresholds agreed with sales before the re-derived model goes live. Rebuilt behaviour scores rarely land on the old numbers, and if MQL now means something different, sales should hear it in a meeting rather than work it out from a thinner queue.
  • The consolidated suppression list verified live before the first send. One list, specified under data and consent.

Watching the platform after cutover is one activity with one name — hypercare — rather than three sets of eyes with different ideas of what they are looking at. It runs from cutover until the parallel period closes. One person is on duty at a time, named on a rota agreed before the go-live date, holding admin rights and able to pause a campaign without asking permission first. The duty list is fixed: the zero-submission alerts built during release engineering; the sync error report, the bounce log and the routing queues; and a reconciliation, by hand, of what the destination created against what the CRM received, every day, until you are bored of it being right. Whoever comes off duty writes down what they saw, so the next person starts from a record rather than a conversation.

What you commit to is continuity of pipeline: leads keep reaching sellers, and the number the forecast is built on stays sound. Say in the same breath that reporting fidelity dips for a period, name which measures go soft, and say what has to be true for them to come back. Put it in the written update, not only in the meeting, so the next person to read it did not have to be in the room.

Quality assurance and release management

QA and cutover: proving it works before anyone finds out it does not

Clicking around finds the faults you already suspected. A matrix finds the others. Every form crossed with every routing outcome it can produce; every nurture with its entry rule and each of its exits; every integration write path, in both directions. Where a workspace or a person partition changes the answer — and when several instances are being folded into one, it usually does — that is another row, not a footnote. The document is dull to read. Dull is the point.

Seed records have to persist. Create them, keep them in a named seed list, and stop tidying them away between test cycles: you want the same people running the same journeys before and after cutover. They live in the seed partition, and they are the same records release engineering builds its environment parity around. Some of them should sit in states the design never anticipated.

  • unsubscribed, then filling in a form with a consent tick
  • two records, same email address, different casing
  • a hard bounce that a sales user has since reactivated by hand
  • someone mid-nurture with a wait step still counting down
  • blank country, on a record whose routing depends on country
  • a record that exists only because a webhook created it overnight, that no human has ever opened, and that has never been explained

Rendering checks are cheap, which is exactly why they get skipped. Run the templates through a rendering service, look at them on a phone, and read the plain-text version — that is usually where a merge token fails loudly. Deliverability is separate work and wants its own owner: DKIM and SPF published for the sending subdomain and verified as propagated rather than merely pasted into a DNS panel, the tracking domain resolving as a separate check, and a warm-up on any sending subdomain that has not sent before.

The parallel run is the only test that proves anything. Both systems capture for a period; you diff the results. Submissions landing in both, field values matching, and — the check people forget — both sides agreeing on who entered which operational program. Alongside it, a standing daily check that nothing has sent from both instances, because that is the failure with an audience. Exit criteria are agreed in advance: a full campaign cycle through the old instance, the diffs clean, the last batch of forms repointed. Meeting them is what triggers the switch-off date already written into the plan. Everything else tests the design you had in your head. This tests the one you built. It gets read as a scheduling cost; we treat it as the cheapest quality gate on the plan.

The go/no-go is the acceptance criteria written at discovery, with thresholds attached and an owner named against each one. One document carried forward, not a fresh one drafted the week before, and the rollback trigger sits inside it as a criterion. Agree the thresholds while everyone is calm. The part that gets left out is a written position on what counts as an acceptable known defect. Without it, the decision gets made at six on a Friday by whoever has the least energy left to object.

Someone who did not build the operational programs should review them. This catches the class of failure that testing misses: the smart campaign whose logic is right and whose filter still points at the old list; the sync user's profile missing field-level edit rights on one field, so writes fail silently and nothing anywhere raises an error; a form whose post endpoint is not on the repointing register, still posting to a handler with a switch-off date against it. Reviewing another person's migrated work is slow and low-status — you compare screens against a specification, find nothing, find nothing, then find one thing — and it is where the expensive mistakes get caught, so it belongs in the plan with a name against it rather than in whatever capacity is left over.

None of this stops at cutover. The seed list keeps running its journeys and the parallel-run diffs keep being produced; both become entries on the hypercare duty list, worked by whoever is on the rota that day.

The part most plans leave implicit

Migrations stall where ownership is assumed rather than agreed. This is the split we work to, and we write it down before the first export.

PhaseOwns itHas to be consulted
Inventory and dispositionDiscoveryData & consent · Revenue continuity
Long-lead requestsSequencingRelease engineering
Instance architecture and field mapSequencingData & consent · Release engineering
Consent, suppression, dedupe, retentionData & consentDiscovery · QA & cutover
Build, version control, environmentsRelease engineeringSequencing · QA & cutover
Test matrix, parallel run, go/no-goQA & cutoverRelease engineering · Revenue continuity
Cutover, hypercare, reportingRevenue continuityRelease engineering · QA & cutover

Bring us the messy version

The migration that stalled, the instance someone else half-built, the acquisition that left you with three databases. A free 30-minute call and a system audit will tell you what the work actually is.