Skip to content
Capra Digitals

Migrating 70,000 tickets without losing a record

Volume is not the hard part of a large migration. Proving afterwards that nothing was lost is the hard part.

Published 2 April 2026 · Updated 21 July 2026 · 11 min read · Capra Digitals

The short answer

To migrate 70,000 tickets without losing a record, treat reconciliation as the deliverable rather than the load. Freeze a mapping document that names every source field, its destination property and its transformation rule; run a full dry run into a sandbox and diff record counts, field fill rates and association counts against source; migrate history in batches while the source system stays live; run a delta sync for anything created or edited during the load; cut over in a short read-only window; then produce a reconciliation report comparing counts and checksums per object. If the report does not balance to the record, the migration is not finished.

The part everyone underestimates: associations

Moving 70,000 ticket rows is a batching problem, and batching problems are solved. What breaks migrations is the graph around those tickets — which contact raised it, which company they belong to, which conversation thread and which attachments hang off it.

We migrate in dependency order: companies, then contacts, then deals, then tickets, then engagements and attachments. Every object carries its source system ID into a dedicated HubSpot property so associations can be rebuilt by lookup rather than by guesswork, and so anything can be traced back afterwards.

The mapping document is the contract

Before a single record moves, every source field gets a row: destination property, type, transformation rule, and what happens when the value is empty or unrecognised. Picklist values are enumerated exhaustively — unmatched values are flagged rather than silently dropped.

The client signs this. When someone asks six months later why a field looks different, the answer is a row in a document rather than an archaeology project.

Dry run into a sandbox

  1. 01Load the full dataset into a sandbox portal, not a sample. Samples hide the records that break things.
  2. 02Diff record counts per object against the source.
  3. 03Diff fill rates per property — a field that is 94% populated at source and 61% populated after load is a mapping bug.
  4. 04Count associations per object type and compare.
  5. 05Have two support agents work real tickets in the sandbox for a day. They find what queries do not.

Delta sync and the cutover window

Historical load runs in the background over days while the source system stays fully in use. On cutover day, a delta sync picks up everything created or modified since the snapshot, which is typically a few thousand records rather than seventy thousand.

The read-only window is then under an hour. On the Savance engagement this ran outside US business hours, so agents finished on the old system on a Friday and started in HubSpot on Monday.

Deduplication is a separate project

The same engagement carried around 20,000 duplicate records. Merging during a migration is how you lose data — you are changing two things at once and cannot attribute a discrepancy to either.

Load first with source IDs intact, reconcile, then run deduplication as a controlled second phase with its own before-and-after counts.

PhaseDurationDeliverable
Discovery and mapping2 weeksSigned field mapping document
Sandbox dry run2–3 weeksDiff report, agent test sign-off
Historical load1–2 weeksLoaded portal with source IDs
Delta sync and cutover1 weekendLive portal, <1 hour read-only
Reconciliation and dedupe2–4 weeksReconciliation report, merge log

The reconciliation report

The report lists, per object: source count, destination count, variance and explanation for every variance. Expected variances (test records excluded, soft-deleted rows skipped by agreement) are listed with the rule that produced them. Unexpected variances are worked until they are zero.

This is the artefact that lets a client shut down the old system. Without it, teams keep paying for a legacy licence 'just in case' for years.

Common mistakes

  • Migrating and deduplicating in the same pass, then being unable to explain a count difference.
  • Not writing source system IDs into HubSpot, which makes tracing a specific record impossible afterwards.
  • Testing with a 500-record sample. The broken records are always in the tail.
  • Scheduling cutover on a Monday morning. Cut over when nobody is depending on the system.
  • Treating attachments as an afterthought — they are usually the slowest object to move.

Questions

People also ask

How long does a 70,000-record migration take?

Around four months end to end for the Savance engagement, which combined a Service Hub migration, a 20,000-record cleanup and a three-hub rebuild. A migration of that size on its own is typically six to eight weeks.

Is there downtime during migration?

Historical data loads while the source system stays live. Cutover needs a read-only window of under an hour, usually scheduled outside business hours.

Can you migrate attachments and conversation history?

Yes — attachments, notes, call logs, email threads and task history migrate with timestamps and associations preserved. Attachments are usually the slowest object, so we start them early.

What proves nothing was lost?

A reconciliation report with per-object source counts, destination counts and an explanation for every variance. Anything unexplained is a defect, not a rounding error.

Keep reading

Next step

Want this done in your portal, not just explained?

Bring us the portal as it is. We will tell you what is worth fixing, what it costs and in what order.