Migrating VB.NET to Current .NET: In-Place, C# Rewrite, or Mixed Strategy?
Decide whether to migrate your VB.NET application in place to current .NET, rewrite in C#, or use a mixed-language approach. Compare support, risk, and a concrete validation path.
11 May 2026, 02:53 UTC

The Decision and Its Constraints
You have a working VB.NET application—typically a WinForms desktop tool, WPF client, or class library—running on .NET Framework, and you need it to run on a current .NET release. The core decision is whether to retarget the existing VB code in place, rewrite the logic in C#, or split the solution into mixed-language projects. Microsoft's support statement for .NET 5 and later indicated that Visual Basic remains supported for several app models, including console applications, class libraries, Windows Forms, WPF, worker services, and Web API projects, but the language itself will not receive new feature development. Treat that app-model list as version-sensitive and confirm it against the documentation for the exact .NET release you target.
Three constraints shape the choice. First, unsupported workloads: ASP.NET Core Razor, MVC, and Blazor were excluded from VB support in the 2020 announcement, so new VB web UI projects are not a safe assumption without verifying current support. Second, ecosystem drift: VB receives servicing and security fixes, but the volume of new samples, analyzers, and library examples increasingly favors C#. Third, team continuity: a rewrite discards working domain knowledge and introduces regression risk that an in-place migration avoids.
Comparing the Three Supported Paths
The options are not mutually exclusive, but each has a distinct risk profile.
| Option | What it involves | Primary risk | Best fit |
|---|---|---|---|
| In-place VB migration | Convert to an SDK-style project file, retarget the TFM, fix API breaks | Missing APIs or unsupported app models on the target framework | WinForms, WPF, console, class library, or worker service where the team already knows VB |
| C# rewrite | Translate business logic and UI to C# projects | Regression, lost domain knowledge, extended timeline | New web front-ends, heavy reliance on C#-only constructs, or long-term hiring strategy |
| Mixed-language solution | Keep VB core, add C# modules that reference the same IL output | Solution complexity and dual skill-set maintenance | Incremental migration or preserving VB-specific features such as XML literals |
Because VB.NET and C# compile to the same Intermediate Language (IL)—the common bytecode that runs on the .NET runtime—projects in different languages can reference each other inside one solution. That makes a staged migration possible: you can move high-churn modules to C# while leaving stable VB code untouched.
Trade-offs You Cannot Ignore
Staying in VB preserves developer productivity and minimizes regression risk because existing code, tests, and team skills carry over. The cost is a shrinking ecosystem: fewer modern code samples, third-party analyzers, and job candidates, plus no access to newer C#-only language constructs such as records or advanced pattern matching. A full C# rewrite buys access to the latest language features and a larger talent pool, but for a line-of-business application the translation effort usually outweighs those benefits unless the target workload demands C#.
A mixed-language path balances these forces, but it is not free. You must maintain build ordering, ensure consistent target frameworks, and accept that new developers may need to read both languages. Use it when a specific VB feature—such as XML literals—provides real value, or when you want to prove the migration on one module before committing the entire solution.
A Concrete Validation Path
Do not migrate the whole solution until you have validated the target environment and one representative project.
1. Confirm templates and app-model support
Before touching legacy code, verify that your chosen .NET SDK still ships VB templates for your app model. Open a terminal or Developer Command Prompt where the .NET SDK is installed and run:
dotnet new winforms -lang VB -o <ProjectName> -f <TargetFramework>
Replace <ProjectName> with a scratch directory name and <TargetFramework> with the moniker you plan to use, such as net8.0 or net9.0. No elevated permissions are required. Expected check: the command creates a VB Windows Forms project that restores and builds. If the template is missing or the build fails, your target app model may not be supported for VB in that SDK version.
2. Pilot the Upgrade Assistant on one project
Commit all changes to source control first so you can revert if the retargeting breaks the build. Run the .NET Upgrade Assistant against a small, non-critical project—ideally one with an existing unit-test suite. Convert the project file to SDK style, retarget the framework, and attempt a build. Then run the same tests you ran on .NET Framework and compare results. This pilot exposes API breaks, package compatibility issues, and workload gaps before they affect the whole application.
3. Prototype XML literals if they matter to your codebase
VB's XML literals with embedded expressions let you construct and query XML inline with compile-time syntax checking and axis properties. If your application generates configuration files, reports, or documents, prototype a small module to confirm the tooling behaves as expected. For example:
Dim moduleId As String = "auth"
Dim threshold As Integer = 42
Dim config As XDocument =
<?xml version="1.0" encoding="utf-8"?>
<Configuration>
<Module id=<%= moduleId %>>
<Threshold><%= threshold %></Threshold>
</Module>
</Configuration>
Dim value As Integer = CInt(config...<Threshold>.Value)
The embedded expressions <%= ... %> are checked at compile time, and axis properties such as config...<Threshold> provide concise navigation. Compile this in your target Visual Studio or MSBuild toolchain to verify IntelliSense and code generation still work as expected.
Limitations and a Practical Result Check
Supported means Microsoft will service the runtime and provide security fixes; there is no published deprecation date for VB.NET, so do not plan around an invented end-of-support timeline. Also, VB6 to VB.NET is a port, not an upgrade: array bounds, default properties, and error-handling semantics differ, so budget separately for legacy VB6 sources. The My namespace and some Microsoft.VisualBasic runtime helpers have workload-dependent availability; verify the specific helpers your code uses.
To check whether the in-place migration succeeded, confirm four things: the solution builds on the target .NET version, the existing unit tests pass with results matching the .NET Framework baseline, no unsupported app model is required, and the team accepts long-term maintenance in VB. If any check fails—especially the app-model constraint—plan a staged C# rewrite starting with high-churn modules rather than forcing the VB code onto an unsupported workload.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.