Application modernization

Cloud native application development on Azure

Moving an application off a virtual machine and onto App Service, Container Apps or Azure Kubernetes Service buys real operational properties: no operating system to patch, deployment in minutes, scale that follows demand. It also costs real engineering. Most applications in most estates do not change often enough to earn it, and the useful part of this engagement is knowing which ones do.

Most applications should stay on a virtual machine

That sentence is unusual on a page selling application modernization, so here is the reasoning.

Rehosting a virtual machine is measured in hours and is reversible. Modernizing an application is measured in engineering weeks, touches configuration, state, identity, logging, networking and the deployment process, and is reversible only in the sense that the old server is still switched off somewhere. The return comes from what the platform then does for you every week: patching you no longer perform, releases that take minutes instead of a maintenance window, capacity that follows load instead of being provisioned for the worst hour of the year.

An application that ships twice a year collects almost none of that return. An application that ships weekly collects it continuously. Age is not the variable, and neither is how unpleasant the codebase is to read. Change rate is.

So the first output of this engagement is usually a shorter list than the one we were handed. That is the point of it. A firm that recommends modernizing everything is describing its own capacity plan, not your estate.

The test we apply

How often does it change? Releases per year, from the repository history rather than from memory. This is the strongest single predictor of payback.

What does the virtual machine actually cost? Not the compute line. The patching window, the operating system upgrade waiting in two years, the Windows and SQL Server licenses, and the engineer who is the only one who knows how the service is restarted.

Does the load vary? An application at a flat load all week saves little from elastic scale. An application that is idle overnight and saturated at month end saves a great deal, and Container Apps scaling to zero changes the arithmetic on internal tools.

Is there a support boundary? If the vendor supports the product only on a virtual machine, the decision is made for you. Containerizing a packaged application out of support is trading a patching problem for an unsupported one.

Who operates it afterward? A platform your team can run beats a better platform your team cannot. This question decides between App Service and Kubernetes more often than any technical argument does.

Where applications land

App Service. The default for web applications and APIs. Deployment slots, built-in certificates, autoscale, and no operating system in your care. Most .NET, Java, Node and Python web tiers belong here, and most of the time the migration is a build pipeline plus a configuration change rather than a rewrite.

Azure Container Apps. Background workers, event-driven jobs, scheduled processing and small sets of services that talk to each other. Scale to zero, no cluster to operate, and none of the Kubernetes surface area you would otherwise have to staff.

Azure Kubernetes Service. For genuine multi-service platforms, portability requirements and scaling profiles that justify a cluster. When we recommend it, we design node pools, workload identity, ingress and cost boundaries with it, because an unbounded cluster is a budget incident waiting to happen. When we do not recommend it, we say why in writing.

Azure Functions. Event-driven glue: file arrival, queue processing, scheduled tasks. Often the right destination for the scripts running on a virtual machine that nobody dares reboot.

The data underneath. SQL Server to Azure SQL Managed Instance or Azure SQL Database against a compatibility assessment, PostgreSQL and MySQL to their managed equivalents. The application and its database move together or the exercise is half done.

What the work actually involves

Modernization is mostly unglamorous and it is worth naming, because the estimates that go wrong are the ones that only counted the container build.

State leaves local disk. Sessions, uploaded files and caches move to services designed to hold them, which is usually the change that breaks assumptions written in 2014. Configuration and secrets leave the file system and the connection string, and the application authenticates with a workload identity in Microsoft Entra ID instead of a password in a config file. Logging moves to Log Analytics with correlation that survives across instances. Private networking replaces the implicit safety of a machine on an internal subnet, using private endpoints rather than firewall rules maintained by hand. And the release process becomes a pipeline in GitHub Actions or Azure DevOps, with an environment promotion path and a rollback that has been tested.

Each of those is small. Together they are the engagement, and together they are why an honest plan modernizes a few applications well rather than many badly.

What you keep

  • A scored candidate list, including the applications we recommended against and why.
  • The target platform per application, with the reasoning and the operational cost it removes.
  • Working code in your Git organization from the first commit.
  • Build and release pipelines, with environment promotion and a rehearsed rollback.
  • Runbooks covering deployment, scaling, failure modes and where the logs are.
  • A written baseline of behavior before and after, so a regression argument has evidence.

Who this is for

Organizations already running on Azure, or migrating to it, with a small number of applications that carry real business change and are held back by the machines under them. It is common after a migration has stabilized, and it is common when a development team is shipping fast enough that infrastructure has become the constraint.

It is also for organizations that have been quoted a full rewrite and want a second opinion. Frequently the answer is that two components deserve investment and the rest deserves a supported operating system and a quiet life.

Who this is not for

If the estate has not moved yet, this is not the first engagement. Move first with cloud migration, then modernize what earns it, or decide disposition across the whole portfolio with IT modernization consulting.

If the application is bought, not built, the vendor decides. Modernizing packaged software outside its supported deployment model ends with an unsupported product and a support contract you are still paying for.

If the goal is to reduce the Azure bill, this is the slow route. Cloud cost optimization gets there faster, and right-sizing a virtual machine costs a fraction of rebuilding what runs on it.

Questions we get

How do you decide whether an application is worth modernizing?

Change rate first, then operational cost, then load profile, then the support boundary. An application that ships often, gets patched by nobody in particular and sits idle most of the week is a clear case. An application that has not changed in three years and runs at a steady load is not, whatever its age suggests. The test is written down and applied to every candidate the same way.

Should we use Kubernetes?

Probably not, and saying so costs us revenue. App Service or Container Apps covers most workloads with a fraction of the operational load. Azure Kubernetes Service earns its place when there is genuine multi-service orchestration, a portability requirement or a scaling profile that justifies the cluster, and when someone will still be operating it in two years.

Can you modernize an application you did not write?

Yes, and that is the usual case. What matters is access to the source, a build that runs, and someone who can confirm expected behavior. Where the source is unavailable or the vendor supports the product only on a virtual machine, the honest answer is to retain or rehost it, and we say so rather than containerizing something you can no longer get supported.

Does this have to happen during the migration?

Rarely, and doing both at once is how migrations slip. Rehost first, stabilize, then modernize the small set of applications that earn it, with a working baseline to compare against. The exception is an application already at the end of its operating system support, where moving and changing at the same time avoids paying for the move twice.

What happens to the databases?

They move with the application or they undermine it. SQL Server goes to Azure SQL Managed Instance or Azure SQL Database depending on the compatibility assessment, and PostgreSQL and MySQL estates go to their managed equivalents. Leaving the database on a virtual machine while the application moves to a managed platform keeps every patching obligation you were trying to remove.

Who runs it afterward?

Your team, with the pipelines and the documentation to do it, or us under a managed arrangement, decided before we start rather than after. Modernizing an application into a platform your team cannot operate moves the problem instead of solving it, and we would rather scope a simpler target that actually gets run.

Have a question about this work?

Three fields. An architect reads it and answers within one business day.

Every field is needed.

We reply to this address. Nothing else is sent to it.

The goal, the deadline, and what is in the way. Three lines is plenty.

What you send travels over TLS to our own Azure Function in Canada East and lands in our own Odoo CRM in Montreal. No third-party form script, no advertising cookie. We keep it to answer you, and delete it after twenty-four months if nothing comes of it. Privacy policy.

Bring us the workload. We bring the architecture.

Thirty minutes, one architect, no deck. Come with a problem and leave with an opinion you can act on.