You’re modernizing. Step one: choose a target platform and prepare to defend it until 2036.
When a CTO axes a 400,000-line VB6 monster or a Clinton-era PowerBuilder setup, no one asks if .NET is relevant. The real question is how you defend that choice when Java, Python, TypeScript, and low-code vendors all demand a piece of the pie.
There are four defensible answers. Only one of them is about performance benchmarks, and it's not that interesting.
November 10, 2026 is the date that matters. .NET 8 and .NET 9 both reach end of support on that day. .NET 8's closing its three-year LTS window, .NET 9 is closing an STS window that Microsoft extended from 18 to 24 months, which happens to land both tracks on the same Patch Tuesday. After that date: no servicing updates, no security fixes, no technical support. Applications keep running. They just stop getting patched.
The recommended target is .NET 10, an LTS release supported through November 2028. .NET 11 arrives the same month .NET 8 and 9 expire, and it's an STS release which makes it the wrong place to land a modernization program that's already mid-flight.
Now hold that against .NET Framework 4.8. Framework 4.8.1 has no standalone end-of-support date at all. It's classified as a component of Windows and inherits the lifecycle of the OS it's installed on, which means it will be supported longer than .NET 10, .NET 11, and .NET 12 combined.
This is where a lot of enterprise architecture goes quietly wrong. "Supported" and "evolving" are different products. Framework 4.8 support means Microsoft will keep it from breaking. It doesn't mean new language features, new runtime performance, new hosting models, or new AI libraries. Microsoft's own guidance is that all new development targets modern .NET.
So the lifecycle comparison isn't "three years versus forever." It's:
TargetFramework change plus dependency work, measured in days or weeks, not a rewrite.Teams anchor on the second number because it looks like recurring cost. It's the opposite. A three-year cadence with a one-line version bump is the cheapest insurance policy in enterprise software. The expensive option is the one with no expiration date, because it's the one nobody ever budgets to leave, until the leaving costs seven figures.
The cost of a modernization is not proportional to lines of code. It's proportional to semantic distance. How many concepts in the source language have no faithful equivalent in the target, forcing a human to make a judgment call.
VB6, PowerBuilder, Access, Clarion, and Delphi share a common design DNA: statically typed, event-driven, data-bound, RAD-oriented, built around exact decimal arithmetic and tight database coupling. That's not a coincidence of history. C# was designed by Anders Hejlsberg, who designed Turbo Pascal and Delphi before it. The lineage is direct.
Look at what that buys you in practice. A representative VB6 function:
Public Function GetOrderTotal(ByVal OrderID As Long) As Variant On Error GoTo ErrHandler Dim rs As ADODB.Recordset Dim curTotal As Currency Set rs = gConn.Execute("SELECT Amount FROM OrderLines WHERE OrderID = " & OrderID) Do While Not rs.EOF curTotal = curTotal + rs!Amount rs.MoveNext Loop GetOrderTotal = curTotal Exit Function ErrHandler: GetOrderTotal = Null End Function
And the modern .NET equivalent:
public async Task<decimal?> GetOrderTotalAsync(long orderId, CancellationToken ct = default) { try { return await _db.OrderLines .Where(line => line.OrderId == orderId) .SumAsync(line => (decimal?)line.Amount, ct); } catch (DbException ex) { _logger.LogError(ex, "Order total lookup failed for {OrderId}", orderId); return null; } }
Three things happened, and all three are structure-preserving:
Currency became decimal. Both are exact base-10 types. You're not translating between number systems. You're widening precision. Now try the same function in a JavaScript or Python target. JavaScript's default number type is IEEE-754 binary floating point; you're writing money math in binary fractions or reaching for a library before you write your second function. Python has decimal.Decimal, but it isn't the default and nothing in the type system stops a float from creeping into the aggregation three sprints later. For an accounts-receivable system, that's an audit finding.
On Error GoTo became structured exception handling. Same intent, different mechanics. A genuine translation, but a well-understood one with a single canonical answer.
As Variant returning Null became decimal?. This is the interesting one. In the VB6 original, "this function returns a number, or nothing if it failed" is a convention living in a comment and in the head of a developer who left in 2011. In the C# version it's a type. The compiler enforces it at every call site. Undocumented behavior became checkable behavior, which is exactly what you want out of a modernization and exactly what you don't get from a lift-and-shift.
Caveat: it isn't all this clean. PowerBuilder's DataWindow has no true one-to-one equivalent in any modern stack. The closest analog is a Blazor component bound to an EF Core query, and getting there is legit design work, not translation. Clarion's dictionary-driven code generation and Access's form-plus-macro model have similar gaps. Semantic distance to .NET is short. It isn't zero.
But "short" is the whole game. Every concept that maps cleanly is a concept that doesn't need a human decision, a design review, or a defect eighteen months later in a module nobody remembers.
If a human were doing all the work, semantic distance would just be a cost argument. It isn't a human doing all the work anymore, which changes the calculus.
AI-assisted modernization has a well-documented failure mode: agents get a codebase to roughly 70% converted quickly, then stall in a loop of plausible-looking output that doesn't actually work. The reason is straightforward. An agent generating code needs an oracle; something outside its own judgment that says this is wrong, and here's where.
A statically typed, compiled target hands you that oracle for free. Roslyn is a ground-truth engine: type errors, nullability violations, unreachable branches, and signature mismatches surface deterministically before anything runs, on every iteration, at no cost. The agent gets a hard verification signal on every loop instead of a confident guess.
In a dynamically typed target, that signal doesn't exist. The only oracle is the test suite and if the source is a 30-year-old VB6 application, there is no test suite. That's the whole reason the code is scary. You'd be asking an agent to translate untested legacy logic into a language where nothing checks its work until production does.
This is why the target platform choice is not downstream of the AI-modernization strategy. It is the AI-modernization strategy. A compiler is the cheapest reviewer you will ever hire, and it never gets tired at line 380,000.
Everything above would have been true in 2024. Here's what's new, and it's the reason the question is worth re-asking this year.
Modern .NET is now a first-class platform for building and hosting AI agents, not merely a language you can call an API from:
IChatClient, IEmbeddingGenerator, tool calling, evaluation that you wire up the same way you wire up any other service.Now connect that back to the legacy application. Your VB6 order system contains thirty years of encoded business rules: pricing logic, credit hold conditions, tax treatments, the seventeen exceptions to the return policy that exist in code and nowhere else. Right now that logic is unreachable. No agent can call it, no copilot can reason over it, no workflow can compose with it. It's institutional knowledge locked inside a COM binary running on a Windows Server VM someone is afraid to reboot.
Modernize it to .NET and that same logic becomes a set of typed services. Expose those services through the MCP C# SDK and it becomes agent-callable, discoverable tools that AI systems inside your business can actually use, with governance controls on the call path.
That is the difference between an application that's been upgraded and one that's been modernized. The first one runs on a supported runtime. The second one participates in everything your organization builds next. Every year you stay on the frozen platform, you pay that gap, not in license fees, but in every AI initiative that has to route around your core systems instead of through them.
Here's where .NET is NOT recommended:
What to target
For a modernization program scoping work in the second half of 2026:
|
Decision |
Recommendation |
Why |
|
Runtime |
.NET 10 (LTS) |
Supported through November 2028; avoids landing on a brand-new STS release during migration crunch |
|
Not .NET 11 |
Wait |
STS, GA in November 2026 |
|
UI |
Blazor |
Component model with a C# programming model end to end; keeps one language across the stack |
|
Data |
EF Core |
The closest structural fit for record-set-driven and DataWindow-driven legacy data access |
|
Hosting |
Linux containers on Azure |
Removes per-core Windows licensing from the run-rate; ARM and container density are real cost lines |
|
AI surface |
Microsoft.Extensions.AI + MCP C# SDK |
Makes modernized business logic agent-callable rather than merely running |
Choose .NET in 2026 because the platform is still evolving rather than merely surviving; because the semantic distance from your VB6, PowerBuilder, Access, Clarion, or Delphi source is the shortest available, which directly reduces the amount of the project that requires human judgment; because a compiler gives AI-assisted modernization the verification signal that dynamically typed targets can't; and because a modernized .NET application doesn't just run, it becomes callable infrastructure for everything your organization builds next.
The first three arguments have been true for years. The fourth one is why the question is worth asking again this year.
GAPVelocity AI has been modernizing VB6 and PowerBuilder applications since before .NET existed. Our team built the original VB Upgrade Wizard that shipped with Visual Studio. If you want to know what percentage of your application can be modernized before you commit to a budget, a VELO Assessment will tell you.