Why We Strictly Separate Code and Database Migration in TYPO3 Upgrades
The larger an upgrade becomes, the more important the question of how to organise the process. After more than 150 TYPO3 upgrades, we have come to believe that many projects become needlessly complicated because they follow TYPO3's upgrade path rather than the architecture of the target system.
At first glance, this statement sounds almost contradictory.
Of course, every TYPO3 installation has to go through the official upgrade path. The database migrations, upgrade wizards and breaking changes exist for good reason. No one should try to bypass or shortcut these mechanisms.
Even so, that does not necessarily mean the entire development process has to follow exactly the same order.
It is precisely this distinction that has fundamentally changed our approach to larger TYPO3 upgrades.
The classic route is technically entirely correct
Anyone who has already carried out several TYPO3 upgrades knows the usual procedure.
A project is first brought up to the next supported major version. The code is adjusted just enough for the system to run again; then the upgrade wizards are executed, deprecations are removed and the application is stabilised. Only after that does the same process begin for the next TYPO3 version.
This procedure works.
It follows the evolution of the TYPO3 core consistently and ensures that every database change and every technical adjustment happens in the intended order.
For a long time, we worked exactly this way.
With every larger project, however, we increasingly felt that we were investing a substantial share of our development time in work that created hardly any lasting value for the actual target system.
Solving the same problem several times
A simple example is API changes.
During a classic upgrade, a method is often modernised only just enough to work under TYPO3 9. A few days later, the same spot has to be adjusted again because TYPO3 10 imposes different requirements. After that come further changes for TYPO3 11, TYPO3 12 and finally TYPO3 14.
From a technical standpoint, there is nothing wrong with this.
From an engineering standpoint, however, an unpleasant side effect arises.
A developer deals with the same piece of code multiple times, even though the actual target has long been clear.
The result is often a series of interim solutions that exist solely because the development process follows the individual version steps.
For the eventual system, these interim solutions have no lasting value.
They were merely necessary to reach the next intermediate version.
At some point, we began to question precisely this kind of work.
Two completely different tasks
The real turning point came when we stopped seeing the upgrade as a single process and instead viewed it as two distinct tasks with completely different goals.
The first task concerns the database.
Here there is little room for manoeuvre. The official upgrade wizards of the TYPO3 core have to be run. Tables change, fields are migrated, data structures are adjusted and existing content is transferred into a new schema. This sequence follows the TYPO3 core and should be observed as precisely as possible.
The second task concerns the application code.
Here a very different question arises.
Not:
"How do we get this code onto TYPO3 9 as quickly as possible?"
But rather:
"What should this code look like once the project ultimately runs on TYPO3 14.3?"
These two questions have surprisingly little to do with one another.
The database cares about the journey.
The application code cares solely about the destination.
Our goal is the target architecture
This realisation has changed our projects significantly.
Today, at the start of a larger upgrade, we first define the target architecture.
- Which TYPO3 version should be operated in the long term?
- Which PHP version will be used?
- Which APIs do we want to employ?
- Which third-party extensions will be kept?
- Which components will be replaced?
Only once these questions have been answered do we begin the actual modernisation.
This way we avoid many interim solutions that would have to be removed again later anyway.
From the outset, the code evolves towards the eventual architecture rather than towards an intermediate version that will be abandoned again just a few days later.
The role of our tools
This way of working would hardly be practical without automation, however.
Over many years we have therefore developed tools that support precisely this separation.
An important component is our internal extension Legacy Updater.
It bundles various TYPO3 core upgrade wizards, field-tested migration routines, our own Rector rules and numerous helper scripts that we reuse across many upgrade projects.
The name of the extension is almost beside the point.
What matters is the idea behind it.
If a particular migration step has already been necessary in several projects, it should not have to be developed from scratch each time.
The same applies to our knowledge base.
After every project we document problems, solutions and typical pitfalls. Some insights later become how-tos, others become Rector rules or new features within the Legacy Updater.
With every upgrade, it is therefore not only our experience that grows.
The process itself gets better.
Automation does not replace architecture
This is where a misunderstanding often arises.
Anyone talking about automation can easily give the impression that an upgrade can largely be handled at the push of a button.
Our experience shows the opposite.
In one of our most recently completed enterprise projects, Rector was able to take over roughly forty percent of the actual migration.
That is impressive.
At the same time, however, it also means that sixty percent still required experienced developers.
Not because Rector is inadequate.
But because architectural decisions cannot be automated.
A pi-based extension that has been in production use for fifteen years cannot be migrated to Extbase by a single rule alone.
A custom-built backend module cannot be adapted to modern TYPO3 concepts automatically.
And business logic does not arise from syntax.
It is precisely for this reason that we invest so much time in automation.
Not because we want to replace developers.
But because we want them to be able to concentrate on exactly these tasks.
Why this effort pays off
From the outside, our approach initially looks more elaborate.
- Internal tools
- Checklists
- Deployment scripts
- Regression tests
- A knowledge base
- Our own Rector rules
None of these investments are immediately visible to the end customer.
In the long term, however, they change the economics of a project considerably.
The more reproducible an upgrade becomes, the less time developers spend on recurring routine tasks.
The better changes can be checked automatically, the lower the effort for manual regression testing.
And the more structured a go-live is prepared, the smaller the risk shortly before the actual switchover.
In our view, engineering therefore does not mean programming faster.
Engineering means systematically removing unnecessary work from the process.
An upgrade does not end at go-live
Perhaps that is the biggest difference from our earlier way of working.
In the past, a project ended with a successful migration.
Today, the real improvement often begins there.
After every upgrade, we ask ourselves which insights we can reuse in future projects.
- Which steps can be automated?
- Which problems occurred again?
- Which documentation would have saved time?
- Which decision would we make earlier next time?
It is precisely from these questions that new tools, new rules and new processes emerge.
That is why we no longer see an upgrade as a single project.
We see it as an opportunity to advance the entire engineering process.
What we have learned from this
When we look back today at our first larger TYPO3 upgrades, we would organise many things differently.
Not because the solutions back then were technically wrong.
But because today we distinguish more clearly between what TYPO3 needs for a successful migration and what an engineering team needs for an economical and reproducible project workflow.
The database follows the official upgrade path.
The application code follows the target architecture.
This separation may at first seem like a technical detail.
For us, however, it was one of the most important steps towards delivering large TYPO3 upgrades in a more predictable, more efficient and higher-quality way.
And that is precisely why, in upgrade projects, we now talk far more often about processes than about version numbers.
← Previous articleUpgrade or relaunch? Why the real decision has nothing to do with TYPO3 versionsNext articleAutomating TYPO3 Upgrades
How big is your TYPO3 upgrade?
Estimate the effort and cost of your upgrade in a few minutes — with our TYPO3 upgrade calculator.