Guide
Data warehouse migration: the complete guide to moving legacy logic, and proving it
By Debjani Dhar, Co-founder and CEO and Ted Ghose, Co-founder and CTO · Published · 16 minutes read
The short answer
A data warehouse migration costs what its logic costs, not what its data costs. Count every object, remove the dead code and band each object by complexity. Then move one self-contained domain first and prove it with a reconciliation report per object. Fix the price only after the whole estate is read, and cut over domain by domain so the parallel run ends on a date.
Why does logic, not data, set the cost of a migration?
A migration's cost is set by how many procedures, packages, scripts and jobs the estate holds, not by its terabytes. Data migration is solved. Logic migration is not.
Most of a warehouse is logic nobody can fully explain: procedures written by people who have left, trusted because they have always run. Moving the logic means reading, converting and proving each object.
As Deb puts it, "Migration cost is set by how much logic you have, not how much data." Data volume still matters. It sets how long reconciliation takes to run. It does not set how much effort an object needs to convert.
The wider problem has been measured. In a 2020 McKinsey survey, CIOs estimated tech debt at 20 to 40 percent of the value of their technology estate before depreciation. And 60 percent said it had risen over the past three years. Gartner expects 80% of technical debt to be architectural by 2027 (Magic Quadrant for Technical Debt Management Tools, May 2026). We call the warehouse share of it logic debt.
What should a migration inventory include?
Every unit of convertible logic, counted once, with its type, database, dependencies and schedule. The inventory is the base for the price, the plan and every percentage anyone will quote later.
We count as an object any stored procedure, function, view, trigger or SSIS package. BTEQ scripts, Hive queries and UDFs, Snowflake procedures and tasks, and job definitions count too. Tables belong on the list, but they are rarely where the effort is.
A spreadsheet built from memory is a start, not an inventory. Parse the code itself, because configuration often sits in files, the SSIS catalog and SQL Agent at once. External dependencies, such as linked servers, external schedulers and application databases, go on the list with the object that depends on them.
- Objects by type and database, each counted once
- Lineage: what each object reads from and writes to
- Jobs and schedules, with dependencies in and out of scope
- A complexity band per object
- A dead-code flag per object, with the evidence
- A coverage column: converts by rule, goes to the resolver, stays manual, or not supported
How much of the estate is dead code?
More than most teams expect. Real estates have it, and every dead object you carry over is paid for to convert and then paid for to run.
The evidence for dead code is simple: no caller, no schedule and no reads. Our counting rule removes dead objects from the denominator before any percentage is reported. They are listed separately so you can decide to retire or keep each one. Many teams find the migration is smaller than they feared once the dead code is out.
Dead by reference is not always dead. A procedure may be called from outside the warehouse, or a package run by hand. The business owner of each domain should confirm the list before cutover.
- Tables and views: drop from scope and archive the DDL
- Procedures and functions: drop from scope and confirm with the business owner
- ETL packages: drop from scope and confirm there are no manual runs
- Jobs: disable before cutover rather than delete
How do complexity bands change the plan?
A band per object tells you which code converts by rule, which needs review and which needs an engineer. The split between bands sets the effort more than the total count does.
Two estates with the same count can need very different plans. Band every object before anyone prices the work.
- T-SQL to Spark SQL: collation, NULL handling and date functions differ
- Teradata: QUALIFY, SET tables, implicit casts and macros that depend on volatile tables
- Teradata load logic: FastLoad and TPT steps that sit outside the SQL
- SSIS: precedence constraints and event handlers that carry error logic
| Band | Typical constructs | How it converts |
|---|---|---|
| Low | Set-based SQL, straightforward control flow | By rule |
| Medium | Temp tables, moderate control flow, vendor functions with equivalents | By rule, then reviewed |
| High | Cursors, dynamic SQL, SSIS Script Tasks, recursive joins, vendor functions with no twin | Through the resolver, with an engineer approving |
How do you choose a target platform?
Choose with your own code, not a vendor demo. The count, the dead code and the lineage do not depend on the target, so one inventory can price more than one target.
Novuz converts to Databricks, Microsoft Fabric, Snowflake, Apache Iceberg and Delta Lake. Often the choice is already made by an enterprise agreement or a platform mandate. If it is not, convert a sample of hard objects to two targets side by side and have your engineers read the output.
The output should be native code on the target, with no vendor runtime inside it. If an agent program is under way, ask how the new pipelines will be operated. Agents can run Novuz, and agents can run what Novuz builds: the delivered pipelines can be exposed as MCP tools, under your own access, approvals and audit logging. The conversion in between stays deterministic.
Coverage matters as much as the target. Our sources are SQL Server, SSIS, Teradata including BTEQ, Hadoop (Hive and Impala) and Snowflake. Oracle, mainframe, Informatica, DataStage, Netezza and Redshift are not covered today. Coverage is confirmed per estate during the assessment.
Which domain should move first?
A domain that is self-contained by lineage, with a business owner who will test. We call it the First Domain. It proves the method on your code before you commit the estate.
A domain is a set of objects that share tables and schedules, usually matching a business area. Shared objects, such as reference data, utility functions and logging, are converted first, with the First Domain. After it, the next domains move in parallel and the rest follow the lineage. An estate usually moves in two to six waves.
The First Domain takes 5 to 6 weeks. Its charter states a reconciliation threshold for the agreed objects on the agreed inputs. The default contract threshold is 95% of in-scope objects passing. Miss it at the readout, after the cure period and the charter's exclusions, and the fee is waived or credited. That is the equivalence guarantee, in writing before work starts.
- Week 0: deploy the software in your environment and onboard your engineers
- Weeks 1 to 2: your engineers run the conversion, with us beside them
- Weeks 3 to 4: reconciliation and exceptions
- Week 5: cutover rehearsal and go-live
- Week 6: the expansion readout, with what the domain says about the rest
How do the conversion approaches compare?
There are four broad ways to convert legacy logic: manual rewrite, AI code assistants, platform-native converters and deterministic software. They differ most in what they can prove.
A manual rewrite, in-house or SI-led, is slow and inconsistent. Each engineer rewrites a procedure differently. An SI-led rewrite is priced by the hour against an estimate made before anyone read the code, and that estimate moves.
AI code assistants draft a single object quickly. But they are probabilistic, so the same input can give a different output on the next run. As Ted says, "If a conversion gives a different answer each run, you cannot prove it. Auditors do not accept probabilities." They also hand back files. Deployment, orchestration and proof stay with you.
Platform-native and free converters are a good start for SQL translation to their own platform. They often stop before ETL control flow, orchestration and per-object evidence. Many teams run one first and bring us the remainder.
Deterministic software converts with fixed, versioned rules. Same code in, same code out. About 95% of objects convert by fixed rules; that is the rule share. Under our counting rule, typically 95% or more of objects need no manual edit; that is the automation rate. The rest go to a resolver on a model you approve, at 700 to 1,000 tokens per edge case. Your engineer approves every proposal. Nothing deploys unapproved.
| Approach | Good at | Where it stops | Price basis |
|---|---|---|---|
| Manual rewrite | Anything a person can read | The pace of the few who know the code; no two rewrites alike | Hours |
| SI-led rewrite | Large programs with services around them | An estimate made before reading the code; validation is most of the hours | Hours against an estimate |
| AI code assistants | Quick drafts of single objects | Different output per run; no proof of equivalence; files, not pipelines | Tokens, open-ended |
| Platform-native and free converters | SQL translation to one platform | Often control flow, orchestration and per-object evidence | Free or bundled |
| Deterministic software | Rule-converted objects, each with a report | Coverage is per estate; edge cases need an engineer | Fixed, from an assessment |
What should you ask every vendor to prove?
Ask for the artifact, not the answer. A vendor who cannot produce the artifact has told you what you need to know. These eight requests apply to every vendor, including us.
- A two-run diff: the same source object converted twice, with the diff of the outputs. Ours is empty.
- The counting rule in writing: what counts as converted, what counts as manual, and whether dead code is in the denominator.
- One reconciliation report, for an object you choose rather than one the vendor chooses.
- The dead-code list from your own estate, with the evidence for each object.
- The remedy if the threshold is missed, as contract language rather than a slide.
- A deployment diagram showing where source code, converted code and reports live, and what crosses the network boundary.
- The engineer-approval log for every step that is not rule-based. Ours covers the resolver's share, typically around 5% of objects.
- The ownership and escrow clauses: who owns the output on the day it is produced, and what is held in escrow.
How do you prove a converted object matches the original?
Run the original and the converted logic on the same inputs and compare them, object by object. A reconciliation report per object, marked pass, fail or review, is evidence an auditor can read.
The checks run in order: schema, row counts, column aggregates, sampled rows in a fixed order, then your business-logic checks written as queries. Each report can be exported per object as audit evidence. On delivered estates, reconciliation is above 95% on first pass, typically, and the report names the rest.
Know what the report proves. It shows equivalence on the tested inputs. It does not show that the original was correct. Source objects that give different answers on each run are flagged by design.
Agree the tolerances before the first run, not after the first failure. The people who hold the undocumented rules should add their checks to the reconciliation. They become approvers, not converters.
- The input snapshot, with its location and hash, used on both platforms
- Floating-point tolerance
- Ordering, with any undefined order flagged
- Date, time zone and precision
- Collation and case
How do parallel run and cutover work?
Run old and new side by side one domain at a time, and cut each domain over when its objects pass. The parallel run should end on a date, not when the whole estate is done.
An estate-wide parallel run is the year nobody budgets. Every month it runs, you pay for two platforms. Reconcile per object, by domain, instead. A domain whose objects all pass can cut over on its own. The parallel run then lasts as long as the flagged objects take, not as long as the estate.
Orchestration is rebuilt on the target to the original schedule and dependencies. Production cutover stays your decision.
- Freeze the source for the period, or notify changes in writing so changed objects are reconverted and reconciled
- Confirm the dead-code list and disable dead jobs
- Rehearse the cutover on the target with the rebuilt schedule
- Clear every object marked fail or review, or record why it is accepted
- Have the business owner sign the equivalence record
- Cut over the domain and switch off its legacy jobs
How do renewal and end-of-support dates shape the plan?
They turn a deferred decision into a dated one. Work back from the date, and count the estate first, so you negotiate with two numbers rather than one.
For SQL Server, the dates are public. Extended support for SQL Server 2016 ended in July 2026, and Microsoft lists three years of Extended Security Updates running to July 2029. Extended support for SQL Server 2017 ends in October 2027. Security updates buy time. They do not move the logic.
A Teradata or Snowflake renewal gives you a date and a price. What you lack is the other price: what it costs to leave, fixed. With it, you can renew knowing the exit price, or move some domains first and negotiate on a smaller footprint.
A Hadoop decommission date or a Fabric mandate works the same way. The date does not move, so the plan must end before it.
How long does a data warehouse migration take?
On delivered estates of 1,000 to 1,600 objects, Novuz typically takes 4 to 8 weeks from kickoff to reconciled output. Moving the same logic by hand typically takes a year and a team.
Ask every vendor how they measure time. We count business days from code received to reconciled output, excluding time waiting on the customer. Hand-run timelines slip after the demo, because the demo was conversion. Nobody demos validation.
Your side sets much of the pace. Environment access, input data and a named engineer for approvals sit on the critical path. Functional testing comes on top.
How should you budget, and when can the price be fixed?
Budget on objects and complexity, not hours or terabytes. A price can be fixed only after something has read the whole estate. For Novuz, that is a three-business-day assessment.
We can fix the price because the output is deterministic. The same estate gives the same result, so it can be counted and priced before work starts, with the equivalence guarantee in writing. A firm that bills hours cannot do that. At a fixed price, Novuz is about 40% cheaper than an SI-led rewrite of the same estate.
AI code assistants have no completed-migration baseline to compare against, so we give no percentage there. The honest contrast is a fixed price against open-ended token pricing. Our resolver uses 700 to 1,000 tokens per edge case on your own model, and we add no usage, token or hourly charges.
Keep a line for the work around the conversion: target design, data movement, change management and functional testing. Many teams buy those from their SI.
| Step | Price | Time | What you get |
|---|---|---|---|
| Logic debt scorecard | Free | Ten minutes | A first count and the price band it lands in |
| Estate assessment | $3,000, credited | 3 business days | Every object counted and banded, lineage, dead code, coverage, a fixed price and a recommended First Domain |
| First Domain | $25,000 to $40,000, credited | 5 to 6 weeks | One domain converted, reconciled and cutover-ready, with the equivalence guarantee |
| Full estate | Fixed from the assessment; typically $40,000 to $200,000 for 1,500 to 10,000 objects | By size | Conversion, validation, deployment, parallel-run and cutover support, and 90 days of post-migration fixes |
What are the main risks, and how do you plan for them?
Most risk sits in a handful of constructs and in what a few people know but never wrote down. Name the risks for your estate before work starts, each with its response already in the plan.
Ask what still runs if the vendor disappears: native code with no vendor runtime is the answer you want. Ask too where your code goes. Novuz runs as a container or VM in your cloud or data center, with no outbound connection required. If you choose a hosted model for the resolver, only the edge-case fragments go to it, under your own agreement.
Some estates are not a fit for us. That includes estates under about 300 objects and Oracle-only or mainframe estates. It includes teams with no target and no date inside 18 months, and buyers who want staff augmentation. It also includes organizations that cannot run software in their environment or share code for an assessment.
| Risk | What to do |
|---|---|
| Dynamic SQL built from table contents | Convert to parameterized code, flag for review, reconcile on inputs that exercise each branch |
| C# Script Tasks in SSIS packages | Convert through the resolver, review each proposal, list external calls |
| Cursors and row-by-row loops | Rewrite as set-based operations by rule, and reconcile each rewrite |
| Jobs that depend on an external scheduler | Map where a rule exists, flag where it does not |
| Business rules held by two people | Add their checks to reconciliation and make them approvers |
| Source changes during the migration | Freeze or notify in writing; reconvert and reconcile changed objects |
What should the first 90 days look like?
Count, choose, prove. Read the whole estate in the first month and move one domain in the next six weeks. Then plan the rest with real numbers.
- Week 1: name the date that drives the move and its executive owner. Take the logic debt scorecard for a first count.
- Weeks 1 to 2: share the code for an estate assessment. The three-day clock starts when complete code arrives.
- Weeks 2 to 3: hold the readout. Confirm the dead-code list with domain owners and agree the First Domain, threshold and inputs.
- Weeks 3 to 5: sign the charter, provision the environment and name the engineer who approves resolver proposals.
- Weeks 5 to 11: run the First Domain through conversion, reconciliation, exceptions and a cutover rehearsal.
- Weeks 11 to 12: review what the domain says about the rest: constructs, bands and coverage.
- Week 13: decide on the full estate at a fixed price, set the wave order and give the parallel run an end date.
FAQ
Frequently asked questions
What is the difference between data migration and logic migration?
Data migration moves tables and files to a new platform, and the tools for it are mature. Logic migration moves the stored procedures, ETL packages, scripts and schedules that turn that data into numbers the business trusts. Logic sets the cost, because each object must be read, converted and proven against the original. Data volume mostly affects how long reconciliation takes to run.
What does "converted with no manual edit" mean?
It means an engineer did not change the converted object at all. Under our counting rule, a one-line fix counts as manual, and dead code is removed from the denominator before any percentage is reported. On delivered estates, typically 95% or more of objects convert with no manual edit, a separate figure from the about 95% that convert by rule. Ask every vendor for their counting rule in writing before you compare their percentages.
Can we start before we have chosen a target?
Yes. The object count, the dead code and the lineage do not depend on the target, so an assessment is useful before the decision. It can price Databricks, Microsoft Fabric and Snowflake side by side from the same inventory. If you have no target and no date inside 18 months, though, we will tell you it is too early for a conversion.
Does our code leave our environment?
Not by default. Novuz runs as a container or VM in your cloud or data center, can work air-gapped, and needs no outbound connection. Access goes through your identity provider and every action is logged in your environment. If you choose a hosted model for the resolver, only the edge-case fragments go to it, under your own agreement.
Do we still need a systems integrator?
Often, yes. The conversion becomes software at a fixed price, but the work around it still needs people: target design, data movement, cutover planning, change management and the later waves. Many SIs put the conversion into their own proposal as one fixed line and run the program around it. The platform is available through APIs, so they can drive it from their own tooling.
What happens if the reconciliation threshold is missed?
The First Domain charter states a reconciliation threshold, 95% by default, for the agreed objects on the agreed inputs. Miss it at the readout, after the cure period and the charter's exclusions, and the fee is waived or credited in full. That is the equivalence guarantee. It is in writing before work starts, because the output is deterministic.
Sources
Read next
Last reviewed: