Migrating to current stacks: risks analysed first, then verifiable steps.
I no longer take on maintenance of technically obsolete projects, but I often move them onto current technologies. It is work that needs particular care: a version change often hides libraries to replace, architectures to restructure and configurations to rethink.
Analysis before codeDependencies, licences and risks assessed before choosing the path.
A minimal product, earlyA few features, but runnable, to validate the new architecture.
Why now
In environments with strict security controls, a version that no longer receives updates soon becomes a problem.
Once support ends, security fixes stop. Where security and privacy constraints apply, this can block a release or come up in an audit.
.NET 8 and .NET 9: end of support on 10 November 2026. Microsoft recommends moving to .NET 10, supported until November 2028.
Angular 20: end of long-term support (LTS) on 28 November 2026. Each Angular major version is supported for about 18 months.
AngularJS: unsupported since the end of 2021.
What actually gets migrated
01
The version
The most straightforward case: the same product, in a more recent version.
Even here the jump can be large. Moving from AngularJS to Angular essentially means rewriting the user interface; between Angular versions you go one major version at a time, checking the breaking changes at each step.
Typical paths
AngularJS → Angular
Older Angular → current Angular
.NET Framework → current .NET
Unsupported .NET versions → .NET 10
02
The libraries
Parts built on obsolete libraries often have to be rewritten, mostly on the client side but on the server too.
Many JavaScript libraries hide heavy re-engineering behind a version change. On the server, some have changed licence: this is the case for applications using iTextSharp 4.1.6, the last LGPL version. Later versions are available only under the AGPL or a commercial licence, and for current .NET there is only an unofficial port of 4.1.6.
For each component
How it fits into the rest of the architecture
Licence of the compatible version
Upgrade it, replace it or rewrite the code that uses it
03
The architecture
Adopting current standards means restructuring, not just recompiling.
Many .NET Framework applications use outdated patterns, such as static classes and hand-built dependencies, whereas current .NET is built around dependency injection. Some technologies also have no direct equivalent.
I have migrated Web Forms applications to modern web apps, converting the code-behind into Web APIs, and in one case to Blazor, to stay on an all-Microsoft stack. In the same way I have moved WCF services to REST APIs: here the delicate part is often the data format, because clients took WCF serialisation for granted.
From my experience
Web Forms → web app with Web APIs
Web Forms → Blazor
WCF → REST APIs, compatible with existing clients
Static code → dependency injection
04
The move to the cloud
From a traditional server to the cloud, migration is not only about the application.
Configuration, architecture, permissions and data access have to be analysed and rethought to reach a cloud-ready solution. These are the elements I have dealt with in migrations of this kind.
What needs rethinking
Configuration and secrets, from local files to dedicated services such as Key Vault
Permissions, from Windows accounts to managed identities
Stored procedures and database features not available in the managed service, such as scheduled jobs, cross-database queries and CLR assemblies
Files on disk, in-memory sessions and scheduled tasks, moved to storage, a distributed cache and services such as Azure Functions
The method: risks first, then gradual steps
01
Up-front analysis
An inventory of dependencies, libraries, licences and integrations. For each one, decide whether to upgrade, replace or rewrite it, and which restructuring is needed.
02
Minimal product
The features needed to prove the new architecture holds up, running as early as possible.
03
Feature by feature
A step-by-step plan, with regression tests at every stage.
04
Stakeholders involved early
The people who use the system start trying the migrated parts as soon as they are ready.
05
Old and new side by side
Where possible, the two applications run in parallel. From AngularJS to Angular, users worked with both, to compare them and for the features not yet migrated.
Every migration is a unique path: it depends on where you start, where you want to get to and all of these factors. What does not change is the method: risks analysed first, gradual and verifiable steps.
The initial analysis can also be a stand-alone engagement. More often, with direct clients, it is the first step of a path that leads all the way to the migrated application in production, without the client having to take development in-house.
Coding agents and migration
In migrations I use coding agents with the spec-driven method: starting from the existing code I set the sequence of steps, and alternate the tests run by the agent with hands-on checks.
The agent is least reliable on legacy code, which is exactly where the up-front analysis matters most. Microsoft itself has replaced its upgrade tool, Upgrade Assistant, with an AI-based agent.