What Drives the Cost of a Drupal Migration
How content structure, damaged data and vendor lock-in affect migration estimates, and what to check when comparing quotes.
Padding the Cost
For a customer who wants a second opinion on migration cost, there is often a question: “Is there padding there? Did the developer add padding where it probably does not need to exist?” That question is legitimate, but needs clarification.
Migrations can have different complexity. While uniform data can be mapped and imported easily, less uniform data can result in significant edge cases, pulling additional effort. For example, articles written across a ten-year span can differ in encoding, scripts and styling elements. Those differences show up in the new system, because they relied on markup and styling that the old system had and the new one does not.
In reality, very few migrations have no edge cases. Thus, the question is not whether there is padding, but whether the padding is justified. And that is the question to ask. If the company is not experienced in migrations, or in Drupal, it may blow up the padding to account for risk that comes from its inexperience, rather than the data complexity itself.
What you are Counting is not what you are Paying for
It seems intuitive to estimate the cost by volume. How many pages, how many files. It is the natural measure, because it is the one you can see from outside. On its own, it’s only part of the work involved.
Ten thousand pages of clean, consistently structured content can be a smaller job than four hundred pages built by three different agencies over eight years. Volume affects runtime and validation effort, but it is only part of the estimate. Structural complexity, damaged data and vendor lock-in often require much more developer time.
Five things move the number more than anything else, in my experience:
- Custom data storage and custom building blocks. The previous system invented its own way to store and compose content. Every invention has to be understood, then mapped onto something Drupal already has. The mapping is rarely one to one.
- Vendor-poisoned content. Page builders write their own markup into the body text. Elementor’s in-text markup is the example everyone has met. The content is not really HTML any more. It is that vendor’s dialect, and it renders only inside that vendor’s engine. Extracting meaning from it is its own project.
- Distributed content. The content does not live in one place. Parts come from a CRM, parts from a file share, parts from the CMS, and the finished page is those pieces glued together. The migration now has to reproduce the glue as well as the pieces.
- Legacy content. The fields have accumulated years of changes. A field means one thing in content from 2019 and another in content from 2024, and nothing in the database says so. Somebody has to find each of those seams.
- Corrupted and incomplete content. The most expensive version of this is not technical. It is a vendor who will not export the full content set, or who exports one that is quietly corrupted. You find out after the money is committed.
Where the Complexity Actually Jumps
Drupal handles a lot without complaint. Content types, fields, domains, languages and media are all things it was built for. Adding more of them raises the cost along a fairly straight line. Different content types with their own taxonomies and media are more work than one content type, in roughly the way you would expect.
But composite pages add another layer of work.
When pages are not single documents but compositions, the migration also has to preserve their internal structure. A page assembled from text blocks, image blocks, document blocks and a slideshow, in an order the editor chose, is an assembly that has to be reconstructed. In Drupal this normally means separate paragraph entities as building blocks. Every one of them is an entity with its own fields, its own validation, and its own place in an order that has to survive the move intact.
Before comparing quotes, establish whether your pages are single documents or assemblies of separately stored components. The estimate should account for reconstructing those relationships.
What is Missing from the Quote
These are the items I check for every time. They are the ones that are quietly absent and come back later as change requests. (Sometimes change requests make sense, if it has been agreed from the start that this is how outliers will be handled.)
- Padding for outliers and corrupted data. Covered above, and worth repeating, because the failure mode is specific. If the quote assumes clean data throughout, ask how unexpected cases will be charged.
- Onboarding, analysis and normalisation. Before anything is migrated, the data has to be looked at. Scattered files, content spread across several databases, Windows markup, accumulated corruption. Some of it can be handled during the migration. Some is far cheaper to fix once, before the migration starts. If this work is not named, ask whether it is included and what data has been inspected.
- Test runs and a staging environment. Running test migrations is not optional, and neither is somewhere a human being can open the migrated content and read it. A migration verified by counting rows has not been verified. Budget the final staging pass and the round of checks and polishing that follows it.
- Configuration and editorial work. Somebody sets up the destination content types and fields. Then a person goes through and corrects the rare cases no script will get right. This is human work, it is real, and it is often absent from the estimate.
- Theming. Migrated content was written for another system’s theme. Quote marks, paragraph handling, tables and similar basics relied on styling that is now different or gone. Some of it should be cleaned up during import. Some belongs in the theme layer. Deciding which is which is part of the job, and it has to be paid for in one place or the other.
What Surfaces After Launch
The migration is done, the content is in, everybody has moved on. Then, over the following weeks, a fairly predictable set of things appears. They are worth naming, because together they are the argument for the staging line item above.
- Redirects. Not the obvious ones, which everybody remembers. The custom redirect rules the old system carried. Years of accumulated decisions about renamed sections and campaign URLs, which no longer match anything under a new URL structure.
- Content the old editor handled and CKEditor does not. Markup produced by the previous system’s JavaScript editor arrives in Drupal’s editor, which has its own view about what it will accept. The content is rarely lost outright. It is hidden, or handled differently, which is worse, because nothing reports it.
- Pages that do not render properly. Outliers. Content quietly removed by the text format it landed in, or fields not shown by the display mode that now governs them. The page exists. Part of it does not.
- Embedded JavaScript that stopped working. It ran in the old theme, on the old page, against libraries the old system loaded. None of those are here.
- The slideshow nobody remembered. Something obscure the previous system supported, used once, years ago, on a page that still gets traffic. Neither side knew it existed until it broke.
- Theming details. Quotes, footnotes, asides. The small typographic things the old theme styled, now unstyled or styled as something else.
Checking representative pages and known outliers on staging can uncover these problems before launch. Row counts alone will not show whether content displays correctly or whether an embedded feature still works.
That is why the staging run is a line item rather than a nicety. Finding these problems before launch avoids having to investigate and repair them on a live site.
Warning Signs to Investigate
Three warning signs worth investigating before accepting an estimate:
- the source site was built with a third-party page builder
- the content export arrives as a custom XML format rather than something standard
- the content contains custom, non-HTML markup
If one quote is far below the others, ask how it handles these parts of the migration. The difference may be in the scope, assumptions or approach.
When Two Quotes are Three Times Apart
This is the situation most people are actually in. Two documents for the same brief, and no way to rank them. In my experience the gap comes from one of three places.
Strategy. One quote may cover a basic migration with exceptions billed separately. Another may include a substantial allowance for those exceptions. Compare the assumptions and exclusions, then ask what evidence supports the allowance for your content.
Positioning. Companies have different rates, overheads and commercial priorities. Ask what staffing and support the price includes. A low price does not establish that the work is underfunded, just as a high one does not establish that the migration will be thorough.
Proficiency. A company entering this market, or staffing the work with developers who have not done it before, may need more time for investigation and implementation. Ask about experience with the source system and with migrations of similar complexity.
Compare the totals alongside the scope, exclusions and risks each quote names. References to your page builder, distributed content or legacy fields give you something concrete to discuss. If the estimate is based only on page counts, ask for a review of representative content before committing.