Getting Started

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

The reference material consulted while preparing these pages is listed in the section bibliography.

This page is written against Visual Basic 17.13 on .NET 10 (LTS) with the .NET SDK 10.0.402 and Visual Studio 2026, and was checked on 2026-10-19. .NET 11 was still a release candidate on that date and is treated as upcoming. Every Visual Basic program on the page was built and run with the official mcr.microsoft.com/dotnet/sdk:10.0 container image, with Option Strict On and warnings treated as errors, and the output shown is the real output. The Windows Forms example needs Windows to run, so it was only built. This is the first stop of the reference: it gets a working toolchain, explains how a .vb file becomes a running program, builds the first pieces of the running shelf scenario (a library-catalogue solution that every later page extends), and shows how to read what the compiler and the runtime tell you. The language itself starts on Program Structure and Code Conventions; what Visual Basic can and cannot build on .NET 10 is on Visual Basic and .NET.

Visual Basic (VB) is a statically typed, object-oriented language that compiles to the same intermediate language (IL) as C# and runs on the same runtime. Since 2020 Microsoft has treated it as a stable language: it is supported, it keeps working with new .NET releases, and it receives no new syntax of its own (the details are on History, Versions and Language Strategy). A tool, a library or a Windows desktop application written in VB today is an ordinary .NET project, built with the ordinary dotnet command line.

What you need

Tool What it gives you for Visual Basic Notes

.NET SDK 10

The dotnet command, the Roslyn Visual Basic compiler (vbc), MSBuild, NuGet, the templates, the runtime

Free. Everything on this reference can be built with the SDK alone. Check the installed SDKs with dotnet --list-sdks.

Visual Studio 2026 (Community, Professional or Enterprise)

The full VB experience: project and item templates, IntelliSense, refactorings, code fixes, the Windows Forms and WPF designers, the debugger, Hot Reload, the test explorer, profilers

Windows only. The Community edition is free for individuals and small teams under Microsoft’s license terms. The “.NET desktop development” workload is the one that matters for VB.

Visual Studio Code

Syntax highlighting for .vb files and the dotnet command line in the integrated terminal

There is no Visual Basic language server: the built-in vb grammar provides colors only, and the C# Dev Kit extension is C#-only. Editing works, but without completion, navigation, diagnostics in the editor or a debugger for VB.

Any text editor plus a terminal

dotnet build, dotnet run, dotnet test and the compiler messages

Enough for everything on this page.

For a list of IDEs and editors with links to their official pages, see IDEs & Tools.

The practical consequence of the last two rows is that a Visual Basic developer who wants editor help works in Visual Studio on Windows. The command line is identical everywhere, so a build server, a container image, a Linux or macOS machine or a CI job can build and test a VB solution without any IDE. What cannot be built or run off Windows is the Windows-only part of the platform: Windows Forms, WPF, COM and the My.Computer devices. A Linux or macOS machine can still compile Windows Forms and WPF projects when the project sets EnableWindowsTargeting to true, which is how the examples of this reference that target Windows were checked.

Installing the .NET 10 SDK

Table 1. NET 10 is a long-term support (LTS) release, supported until 2028-11-14, and it is the target of this reference. .NET 8 and .NET 9 reach the end of their support on 2026-11-10. The SDK includes the runtime, so installing the SDK is enough to run what you build.
System Install

Windows

winget install Microsoft.DotNet.SDK.10, or the installer from https://dotnet.microsoft.com/download. Visual Studio 2026 with a .NET workload installs a matching SDK by itself.

macOS

The installer package from the download page or the package manager of your choice. WinForms and WPF projects can be compiled with EnableWindowsTargeting, but not run.

Linux

The distribution’s package manager (Microsoft’s install pages list the package names per distribution) or the install script, or the official container image mcr.microsoft.com/dotnet/sdk:10.0 that this reference uses.

Verify the installation. These are the real outputs of the container used for the examples.

dotnet --version
dotnet --list-sdks
10.0.402
10.0.402 [/usr/share/dotnet/sdk]

Source: dotnet command

When several SDKs are installed, the dotnet command uses the newest one unless a global.json file in the current or a parent directory pins another (global.json overview). A solution that is meant to build identically on every machine usually carries one next to its Shelf.slnx. Which Visual Basic language version you get is decided by the compiler inside the SDK, not by the target framework: an SDK that ships VB 17.13 compiles a net8.0 project with the same language level. The LangVersion property can lower it, as described on History, Versions and Language Strategy.

Installing Visual Studio 2026 for Visual Basic

Run the Visual Studio installer and tick the ".NET desktop development" workload (component id Microsoft.VisualStudio.Workload.ManagedDesktop). That workload contains the Visual Basic compiler and templates, the Windows Forms and WPF designers and the .NET SDK. It can also be added later with the Visual Studio Installer’s Modify command or from the command line with the --add switch of the installer.

What Visual Studio adds to a Visual Basic developer, beyond the SDK:

  • Project and item templates. New Project offers "Console App", "Class Library", "Windows Forms App", "WPF Application" and the test projects with Visual Basic as the language filter. The command-line templates are listed below; the dialog and the command line use the same template engine.

  • The Visual Basic editor features. IntelliSense with the VB keyword and My completion, the background compiler that underlines BC errors as you type, refactorings and code fixes, automatic line-continuation handling, and the pretty lister that corrects keyword case and indentation on every Enter. Visual Basic is case-insensitive, and the editor normalizes identifier case to the declaration, which is why Console.WriteLine, console.writeline and CONSOLE.WRITELINE compile identically and the editor shows the first form.

  • Designers. A drag-and-drop designer for Windows Forms and a XAML designer for WPF, which write the generated partial class for you (shown at the end of this page).

  • Debugging. Breakpoints, watches, Edit and Continue and Hot Reload work for Visual Basic projects on .NET 6 and later.

  • Test Explorer, coverage and profilers, covered on Testing and Debugging and Diagnostics.

Two points in the editor are worth setting up once, before the first project. Open Tools, Options, Projects and Solutions, VB Defaults and check that Option Strict is On (the page on Option Statements explains why the default is Off, and why you want to override it), and that Option Explicit and Option Infer are On. These settings only affect projects created from the dialog; the project file and the first line of each source file win over them.

Visual Studio Code and other editors

Visual Studio Code ships a built-in vb extension that provides a TextMate grammar (syntax colors), a few code snippets and a language configuration (brackets, comment markers), and nothing else. There is no language server for Visual Basic, and the Microsoft C# Dev Kit works on C# projects only. In practice this means:

  • No completion list, no go-to-definition, no rename and no diagnostics in the editor. Mistakes are found by running dotnet build in the terminal and reading the BC errors, as in the section on diagnostics below.

  • No debugger integration for Visual Basic. A terminal-only workflow can use Console.WriteLine, Debug.WriteLine and the Visual Studio debugger on a Windows machine when needed.

  • Everything that is a command works: dotnet new, dotnet build, dotnet run, dotnet test, dotnet watch, dotnet format and NuGet restore.

Use Visual Studio when you write a lot of Visual Basic, Visual Studio Code or a plain editor for reading, small edits and CI work. Third-party IDEs may add their own VB support; this reference does not rely on any of them.

"Hello, world!"

A Visual Basic console program is a Module with a Sub Main. There is no class around it and no static keyword: a Module is a type whose members are all implicitly shared, which is exactly what the entry point needs.

Option Strict On

Module Program

    Sub Main()
        Console.WriteLine("Hello, world!")
    End Sub

End Module
Hello, world!

Reading the program line by line:

  • Option Strict On is a file-level compiler option that must be the first statement of the file. It turns off the implicit conversions and late binding that Visual Basic still allows by default. Every example in this reference starts with it; the reason and the other Option statements are on Option Statements.

  • Module Program ... End Module declares the module. Its name is up to you; Program is the convention of the templates. A project may contain several modules and the compiler needs to know which Main to call: when exactly one Sub Main or Function Main is found, it is the entry point.

  • Sub Main() is the entry point. It may take args As String() to receive the command-line arguments, and it may be a Function Main(...) As Integer that returns the process exit code. Main is not case-sensitive, like everything else.

  • Console needs no Imports System: the SDK adds global imports for Microsoft.VisualBasic, System, System.Collections, System.Collections.Generic, System.Diagnostics, System.Linq, System.Threading.Tasks and System.Xml.Linq to every VB project. The Imports statement of the generated template is therefore redundant but harmless.

  • Blocks are closed by End plus the keyword (End Sub, End Module, End If). There are no braces and no semicolons, and a statement ends at the end of the line.

A program that returns an exit code and reads its arguments uses Function Main. The next program also shows where the runtime pieces come from.

Option Strict On

Imports System.Reflection
Imports System.Runtime.InteropServices

Module Program

    Function Main(args As String()) As Integer
        Dim vbRuntime As String = GetType(Microsoft.VisualBasic.Constants).Assembly.GetName().Name
        Console.WriteLine($"Framework : {RuntimeInformation.FrameworkDescription}")
        Console.WriteLine($"Entry     : {Assembly.GetEntryAssembly().GetName().Name}")
        Console.WriteLine($"VB runtime: {vbRuntime}")
        Console.WriteLine($"Arguments : {args.Length}")
        Return 0
    End Function

End Module

Run with dotnet run — a b (the -- separates the arguments of dotnet run from those of the program):

Framework : .NET 10.0.13
Entry     : hello2
VB runtime: Microsoft.VisualBasic.Core
Arguments : 2

The Visual Basic runtime library (Microsoft.VisualBasic.Core, with the Windows Forms part in Microsoft.VisualBasic.Forms) is the assembly that holds Left, Mid, CInt, Format, MsgBox, the Like operator helpers and the My support. It ships with .NET and is referenced automatically. The assembly name hello2 above is simply the name of the project file in the scratch directory.

There are no top-level statements

C# 9 allows statements directly in the file. Visual Basic does not, and the compiler says so:

Option Strict On

Console.WriteLine("Hello, world!")
/w/Program.vb(3,1): error BC30689: Statement cannot appear outside of a method body.

The cure is the Module and Sub Main above. Visual Basic also has no Async Main: an asynchronous program starts in a Sub Main that waits for the task, as shown on Async and Await.

Creating a console project

The same project can be created in Visual Studio (File, New, Project, "Console App" with the language set to Visual Basic) or with one command. The command is what the rest of this reference uses, and Shelf.Cli is the name of the console front of the shelf scenario.

dotnet new console -lang VB -o Shelf.Cli

The -lang VB switch matters. Without it dotnet new creates a C# project, because C# is the default language of every template. The templates that exist for Visual Basic on the SDK used here are:

Template Name                  Short Name           Language  Tags
-----------------------------  -------------------  --------  -----------------------
Class Library                  classlib             C#,F#,VB  Common/Library
Console App                    console              C#,F#,VB  Common/Console
MSTest Test Class              mstest-class         C#,F#,VB  Test/MSTest
MSTest Test Project            mstest               C#,F#,VB  Test/MSTest/Desktop/Web
NUnit Test Item                nunit-test           C#,F#,VB  Test/NUnit
NUnit Test Project             nunit                C#,F#,VB  Test/NUnit/Desktop/Web
Windows Forms App              winforms             C#,VB     Common/WinForms
Windows Forms Class Library    winformslib          C#,VB     Common/WinForms
Windows Forms Control Library  winformscontrollib   C#,VB     Common/WinForms
WPF Application                wpf                  C#,VB     Common/WPF
WPF Class Library              wpflib               C#,VB     Common/WPF
WPF Custom Control Library     wpfcustomcontrollib  C#,VB     Common/WPF
WPF User Control Library       wpfusercontrollib    C#,VB     Common/WPF
xUnit Test Project             xunit                C#,F#,VB  Test/xUnit/Desktop/Web

That list is the output of dotnet new list --language VB. Two things stand out. There is no VB template for a worker service, a web API, an MVC or Razor application, Blazor, gRPC or .NET MAUI: those workloads are not available to Visual Basic (the app-model table on Visual Basic and .NET explains the options, which are a Visual Basic class library hosted from a C# application, or hand-written code). And the "Console App (.NET Framework)", "Windows Forms App (.NET Framework)" and "Blank App (UWP)" templates that older Visual Studio offered are not part of the SDK templates: they belong to .NET Framework 4.8.1 projects, which Visual Studio still supports for maintenance.

The generated files

The command creates a folder with two files, plus the obj folder that the first restore adds.

Imports System

Module Program
    Sub Main(args As String())
        Console.WriteLine("Hello World!")
    End Sub
End Module
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <RootNamespace>Shelf.Cli</RootNamespace>
    <TargetFramework>net10.0</TargetFramework>
  </PropertyGroup>

</Project>

These are the files exactly as the template wrote them. Notice what they do not contain: there is no Option Strict On in the source and no OptionStrict in the project. A freshly generated Visual Basic project therefore compiles with Option Strict Off, which allows the implicit narrowing conversions and the late binding that the rest of this reference teaches you to avoid. The first thing to do with the template is to switch the option on in the project file:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <RootNamespace>Shelf.Cli</RootNamespace>
    <TargetFramework>net10.0</TargetFramework>
    <OptionStrict>On</OptionStrict>
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
  </PropertyGroup>

</Project>

The SDK’s own defaults for the Visual Basic properties, read back with MSBuild on the SDK used here, are OptionExplicit On, OptionInfer On, OptionStrict Off and OptionCompare Binary. A section of a solution can set them once for every project in a Directory.Build.props file at the solution root, and that is what the shelf solution does:

<Project>
  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>
    <OptionExplicit>On</OptionExplicit>
    <OptionStrict>On</OptionStrict>
    <OptionInfer>On</OptionInfer>
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
  </PropertyGroup>
</Project>

Every property of the project file, and every Visual Basic compiler option behind it, is covered on Projects, MSBuild and the dotnet CLI. Three properties deserve a word here.

RootNamespace

The namespace that the compiler puts around every type of the project, in addition to any Namespace block in the file. This is a Visual Basic-specific rule and the source of a classic first-day surprise: if the project’s RootNamespace is Shelf.Core and a file declares Namespace Shelf.Core, the type ends up in Shelf.Core.Shelf.Core. The shelf solution therefore writes no Namespace block for its top-level types and lets the root namespace do the job. C# has no such property and always uses the namespace written in the file.

TargetFramework

net10.0 runs on every platform. net10.0-windows adds the Windows-only APIs (Windows Forms, WPF, and the Windows registry and COM types). net481 targets the last .NET Framework. The moniker table is on Visual Basic and .NET.

OutputType

Exe for a console program, WinExe for a graphical one (no console window), Library (the default) for a class library.

Build, run and the output folder

dotnet run --project Shelf.Cli
dotnet build Shelf.Cli
Hello World!
  All projects are up-to-date for restore.
  Shelf.Cli -> /w/Shelf.Cli/bin/Debug/net10.0/Shelf.Cli.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.43

The folder bin/Debug/net10.0 then contains Shelf.Cli.dll (the IL assembly), Shelf.Cli.pdb (debug symbols), Shelf.Cli.runtimeconfig.json and Shelf.Cli.deps.json (how the host finds the framework and the dependencies) and, on Windows, the launcher Shelf.Cli.exe (on Linux and macOS a launcher without extension). dotnet run builds first when the sources changed, so dotnet build is only needed when you want the build without running.

Source: dotnet build

How a build turns .vb files into a program

The figure follows one project from source to a running process. The key points are that Visual Basic is compiled ahead of time to IL, not to machine code, and that the same runtime that executes C# executes the result.

From .vb sources and the .vbproj file through MSBuild and the Roslyn Visual Basic compiler to a .dll with a .pdb, then the dotnet host, the CLR and the JIT compiler

Step by step:

  1. Restore. NuGet resolves the package references and the reference assemblies of the target framework into obj/project.assets.json. This is the step that needs the network the first time.

  2. Evaluate. MSBuild reads the .vbproj and every props and targets file it imports, starting with Microsoft.NET.Sdk and Directory.Build.props. The Visual Basic parts of the SDK add the global imports listed earlier, the Option properties, the default DefineConstants (CONFIG, DEBUG, TRACE, PLATFORM) and the reference to Microsoft.VisualBasic.Core.

  3. Compile. The Vbc task of MSBuild runs the Roslyn Visual Basic compiler, the vbc.dll that ships inside the SDK folder (Roslyn/bincore), often through the shared compiler server VBCSCompiler that stays alive between builds to make them faster. The compiler parses the sources, binds every name and type (enforcing Option Explicit, Option Strict and the others), reports BC errors and warnings, and emits the assembly.

  4. Output. The assembly (.dll, or .exe-style launcher plus .dll) contains IL and metadata. The .pdb maps IL back to source lines. The runtime configuration files are small JSON documents.

  5. Run. dotnet run, dotnet Shelf.Cli.dll and the apphost all do the same: the host (hostfxr) reads runtimeconfig.json, finds Microsoft.NETCore.App 10.0, starts the Common Language Runtime and calls the entry point. Methods are compiled from IL to native code by the JIT compiler the first time they run.

Because the compiler is the same Roslyn platform as C#'s, an assembly built from Visual Basic is indistinguishable at run time from one built from C#: another .NET language can reference it and call it, and the reverse is true (see Interop with C# and Other .NET Languages).

The shelf scenario starts here

From this point every page of the reference uses the same small solution, Shelf.slnx: a library catalogue of books and magazines, with a console front (Shelf.Cli), data access (Shelf.Data), Windows Forms and WPF fronts, tests and a tiny legacy corner. The first brick is a function that checks an ISBN-13: thirteen digits, with hyphens allowed, whose check digit makes the weighted sum a multiple of ten (digits at even positions count once, at odd positions three times).

The library lives in Shelf.Core, which is a class library. A class library has no entry point, so the code is a Module of shared functions, the Visual Basic counterpart of a C# static class.

Option Strict On

Public Module IsbnChecker

    ''' <summary>Returns True when text is a valid ISBN-13 (hyphens allowed).</summary>
    Public Function IsValid(text As String) As Boolean
        Dim digits As New List(Of Integer)
        For Each ch As Char In text
            If Char.IsDigit(ch) Then
                digits.Add(AscW(ch) - AscW("0"c))
            ElseIf ch <> "-"c Then
                Return False
            End If
        Next
        If digits.Count <> 13 Then
            Return False
        End If

        Dim sum As Integer = 0
        For i As Integer = 0 To 12
            sum += If(i Mod 2 = 0, digits(i), digits(i) * 3)
        Next
        Return sum Mod 10 = 0
    End Function

End Module

A few Visual Basic features appear in those twenty lines and are explained on their own pages: If(a, b, c) is the conditional operator (Operators and Expressions), For i As Integer = 0 To 12 has an inclusive upper bound, Mod is the remainder operator, AscW converts a character to its UTF-16 code, and ''' starts an XML documentation comment (XML Documentation, Analyzers and Code Style). The console front calls it:

Option Strict On

Imports Shelf.Core

Module Program

    Function Main(args As String()) As Integer
        If args.Length = 0 Then
            Console.Error.WriteLine("usage: Shelf.Cli <isbn> [<isbn> ...]")
            Return 2
        End If

        Dim invalid As Integer = 0
        For Each text As String In args
            Dim ok As Boolean = IsbnChecker.IsValid(text)
            Console.WriteLine($"{text,-18} {If(ok, "valid", "invalid")}")
            If Not ok Then
                invalid += 1
            End If
        Next
        Return If(invalid = 0, 0, 1)
    End Function

End Module

dotnet run --project Shelf.Cli — 978-0-306-40615-7 978-0-306-40615-8 abc printed the following, and the process exit code was 1 because two of the three arguments were invalid. Run without arguments, the program printed its usage line on the error stream and exited with code 2.

978-0-306-40615-7  valid
978-0-306-40615-8  invalid
abc                invalid

Imports Shelf.Core makes the types in the root namespace of the library visible. The reference from Shelf.Cli to Shelf.Core is a project reference, added in the next section.

A class library, a test project and a solution

A solution groups projects so that one command builds them all. Since .NET 10 dotnet new sln creates the XML-based .slnx format (the older .sln format is still supported). The commands below create the three projects of this page, put them in a solution and connect them. Each line is followed by the message the SDK printed.

dotnet new sln -n Shelf
dotnet new console -lang VB -o Shelf.Cli
dotnet new classlib -lang VB -o Shelf.Core
dotnet new mstest -lang VB -o Shelf.Tests
dotnet sln add Shelf.Cli Shelf.Core Shelf.Tests
dotnet add Shelf.Cli reference Shelf.Core
dotnet add Shelf.Tests reference Shelf.Core
The template "Solution File" was created successfully.
The template "Console App" was created successfully.
The template "Class Library" was created successfully.
The template "MSTest Test Project" was created successfully.
Project `Shelf.Cli/Shelf.Cli.vbproj` added to the solution.
Project `Shelf.Core/Shelf.Core.vbproj` added to the solution.
Project `Shelf.Tests/Shelf.Tests.vbproj` added to the solution.
Reference `..\Shelf.Core\Shelf.Core.vbproj` added to the project.
Reference `..\Shelf.Core\Shelf.Core.vbproj` added to the project.

The resulting solution file is this small XML document, and the reference commands added a ProjectReference item to the .vbproj of the console and the test project:

<Solution>
  <Project Path="Shelf.Cli/Shelf.Cli.vbproj" />
  <Project Path="Shelf.Core/Shelf.Core.vbproj" />
  <Project Path="Shelf.Tests/Shelf.Tests.vbproj" />
</Solution>
<ItemGroup>
  <ProjectReference Include="..\Shelf.Core\Shelf.Core.vbproj" />
</ItemGroup>

The class library project is the smallest possible one: a RootNamespace and a TargetFramework, no OutputType (the default is Library), and a Class1.vb that the template creates and that the page replaces by IsbnChecker.vb. The test project created by the MSTest template references the MSTest NuGet package and, in the template used here, sets LangVersion to latest and the properties ImplicitUsings and Nullable to enable. Neither property does anything for Visual Basic: VB has no nullable reference types (see Nothing and Nullable Value Types), and a console project with ImplicitUsings enabled still could not see HttpClient without Imports System.Net.Http (BC30002). The global imports of a VB project are the fixed list given earlier, not the C# implicit usings. The template also adds a settings file with an assembly-level Parallelize attribute that tells MSTest to run test methods in parallel. A first test for the ISBN checker, with Option Strict On and the references to the library:

Option Strict On

Imports Microsoft.VisualStudio.TestTools.UnitTesting
Imports Shelf.Core

<TestClass>
Public Class IsbnCheckerTests

    <TestMethod>
    Public Sub AcceptsValidIsbn13WithHyphens()
        Assert.IsTrue(IsbnChecker.IsValid("978-0-306-40615-7"))
    End Sub

    <TestMethod>
    Public Sub RejectsWrongCheckDigit()
        Assert.IsFalse(IsbnChecker.IsValid("978-0-306-40615-8"))
    End Sub

End Class

With OptionStrict On and TreatWarningsAsErrors set in the three projects, dotnet build Shelf.slnx and the test run gave:

  Shelf.Core -> /w/Shelf.Core/bin/Debug/net10.0/Shelf.Core.dll
  Shelf.Cli -> /w/Shelf.Cli/bin/Debug/net10.0/Shelf.Cli.dll
  Shelf.Tests -> /w/Shelf.Tests/bin/Debug/net10.0/Shelf.Tests.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Passed!  - Failed:     0, Passed:     2, Skipped:     0, Total:     2, Duration: 9 ms - Shelf.Tests.dll (net10.0)

The test command is dotnet test Shelf.Tests (a project) or dotnet test from a folder that has one project or solution. The shelf reference has the same tests in MSTest, xUnit and NUnit variants, compared on Testing. A new test project of a solution is a good habit even for a toy: it is the quickest way to run a function without a Main.

Opening Shelf.slnx in Visual Studio 2026 loads the three projects, and the same build, run and test commands exist as menu items. Pressing F5 starts the startup project under the debugger, as described below.

A first Windows Forms form

The shelf has a desktop front, Shelf.Desktop. Creating the project is another template:

dotnet new winforms -lang VB -o Shelf.Desktop

The template writes a project with OutputType WinExe, the target framework net10.0-windows, UseWindowsForms set to true, a Program.vb with a Sub Main that starts the application on the first form, and a form split in two files: Form1.vb for your code and Form1.Designer.vb for the code the designer writes. This split is the Visual Basic Partial Class mechanism, covered on Classes and Objects. The designer file declares the controls as Friend WithEvents fields and creates them in InitializeComponent; your file contains the event handlers, bound with the Handles clause.

Option Strict On

Public Class Form1

    Private Sub GreetButton_Click(sender As Object, e As EventArgs) Handles GreetButton.Click
        MessageLabel.Text = "Hello, world!"
    End Sub

End Class

The relevant lines of the designer file for that form are these:

Friend WithEvents GreetButton As Button
Friend WithEvents MessageLabel As Label

Private Sub InitializeComponent()
    components = New System.ComponentModel.Container()
    GreetButton = New Button()
    MessageLabel = New Label()
    SuspendLayout()
    GreetButton.Location = New Point(24, 24)
    GreetButton.Name = "GreetButton"
    GreetButton.Size = New Size(120, 32)
    GreetButton.Text = "Greet"
    MessageLabel.AutoSize = True
    MessageLabel.Location = New Point(24, 72)
    MessageLabel.Name = "MessageLabel"
    AutoScaleMode = AutoScaleMode.Font
    ClientSize = New Size(320, 120)
    Controls.Add(GreetButton)
    Controls.Add(MessageLabel)
    Text = "Shelf"
    ResumeLayout(False)
    PerformLayout()
End Sub

Built, not run: the form needs Windows to display. The project built on the Linux container with -p:EnableWindowsTargeting=true (set in the project) and gave Build succeeded with no warnings. The Handles GreetButton.Click clause is what connects the button to the method; compare it with the AddHandler statement and with C#'s += on Events and Handlers, and see Windows Forms Applications for the full application, including the Visual Basic Application Framework and My.Application.

Reading compiler diagnostics

Every message from the Visual Basic compiler has the form file(line,column): severity code: text, where the code is BC followed by a number (BC means Basic Compiler). Errors stop the build, warnings do not unless TreatWarningsAsErrors is set. The following small file has five different mistakes, and the compiler’s five messages, copied from the build, show how much they say.

Option Strict On

Module Program

    Function Triple(n As Integer) As Integer
        Return n * 3
    End Function

    Sub Main()
        Dim title As String = 42
        Console.WriteLine(Triple(1, 2))
        Console.WriteLine(title.Lenght)
        Dim count As Integer = "7"
        If title = Nothing Then Console.WriteLine("x")
        Console.WriteLine(Triple("7"))
    End Sub

End Module
/w/Program.vb(10,31): error BC30512: Option Strict On disallows implicit conversions from 'Integer' to 'String'.
/w/Program.vb(11,37): error BC30057: Too many arguments to 'Public Function Triple(n As Integer) As Integer'.
/w/Program.vb(12,27): error BC30456: 'Lenght' is not a member of 'String'.
/w/Program.vb(13,32): error BC30512: Option Strict On disallows implicit conversions from 'String' to 'Integer'.
/w/Program.vb(15,34): error BC30512: Option Strict On disallows implicit conversions from 'String' to 'Integer'.

This is a deliberately failing program; it does not build, which is the point. The same statements Dim count As Integer = "7" and Triple("7") compile without any diagnostic when Option Strict is Off and silently convert the text at run time (a project that did this printed 28 when it added them). That is why this reference sets the option on everywhere, and why the first diagnostic you will see in practice is BC30512.

Code Message pattern Usual cause and cure

BC30451

'name' is not declared. It may be inaccessible due to its protection level.

A misspelled identifier, a missing Imports, a variable declared in an inner scope, or a member that is Private. With Option Explicit On (the default) every variable must be declared with Dim.

BC30002

Type 'name' is not defined.

A misspelled type, a missing Imports or a missing project or package reference.

BC30456

'member' is not a member of 'type'.

A typo (as above), or a member that exists only on another type or in another version of the API.

BC30057

Too many arguments to 'method'.

Wrong call shape; read the signature that the compiler prints.

BC30512

Option Strict On disallows implicit conversions from 'A' to 'B'.

A narrowing or text-to-number conversion. Convert explicitly with CInt, Integer.Parse, CType or DirectCast; see Type Conversions.

BC30689

Statement cannot appear outside of a method body.

Code placed directly in a file or class; there are no top-level statements.

BC42104 (warning)

Variable 'name' is used before it has been assigned a value. A null reference exception could result at runtime.

A reference-type local read before assignment. It is a warning, which TreatWarningsAsErrors turns into an error.

Learn’s error-message index documents many BC numbers on its own page under the misc path (the number is the last segment of the address), but some common ones, such as BC30451, BC30002 and BC42104, have no page of their own at the time of writing, so a search for the number and the message text is the way to find explanations. The message itself usually already contains the fix.

Reading tips that save time:

  • Fix the first error of a build and rebuild. Several later messages are often consequences of the first one (a missing End If causes errors far below it).

  • The line and column point to the start of the expression that failed, not always to the cause. A BC30512 on a Dim line may really be a wrong type on the right-hand side.

  • A warning is a real finding. Warnings that matter most, such as BC42104 above, are the compiler telling you that a run-time exception is likely. With TreatWarningsAsErrors set, the warning stops the build and cannot be ignored by accident.

  • Several statements per line are allowed with a colon (Dim a = 1 : Dim b = 2), but a long line is rarely the clearest style. Line continuation is implicit after many tokens since Visual Basic 10, so a statement can span lines without an underscore, as shown on Program Structure and Code Conventions.

A run-time exception

The compiler cannot catch everything. The BC42104 warning of the previous table disappears when the variable is explicitly set to Nothing, because the compiler no longer sees a missing assignment, and the failure moves to run time:

Option Strict On

Module Program

    Sub Main()
        Dim name As String = Nothing
        Console.WriteLine(name.Length)
    End Sub

End Module
Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
   at err.Program.Main() in /w/Program.vb:line 7

The runtime prints the exception type, its message and the stack trace (err is the project name of the scratch project) and ends the process with a non-zero exit code; the container returned 134 on Linux, and on Windows the code differs. NullReferenceException is the most common exception in VB code, because Nothing is a valid value of every reference type; Nothing and Nullable Value Types and Structured Exception Handling show the guards (Is Nothing, the ?. operator, Try ... Catch). The line number in the stack trace is available because the debug symbols (.pdb) sit next to the assembly.

Running with the debugger

In Visual Studio, set a breakpoint with F9 on a line and start with F5 (Debug, Start Debugging); Ctrl+F5 runs without the debugger. At the breakpoint the Locals and Watch windows show the variables, F10 steps over a statement, F11 steps into a call, and Shift+F11 steps out. Edit and Continue lets you change code while stopped, and Hot Reload applies code changes to a running application, for Visual Basic on .NET 6 and later. The debugger also stops on an unhandled exception at the exact line, with the exception helper showing the message and the inner exception.

Without Visual Studio, a Visual Basic program is debugged with logging: Debug.WriteLine (removed from release builds, because the DEBUG constant is defined only in Debug configuration), Trace.WriteLine, Console.Error.WriteLine, and the stack trace of an exception. dotnet watch run rebuilds and restarts the application each time a file changes. The page on Debugging and Diagnostics covers the debugger, Debug and Trace, the Stop statement, dumps and counters.

Where the books are outdated for this page

Both books that this section draws on were written for earlier tooling, and their getting-started chapters are the part that aged fastest. They are credited on the section’s bibliography.

What the books say Current state (checked on 2026-10-19)

Visual Basic is part of the .NET Framework; the console project is the "Console App (.NET Framework)" template.

Visual Basic targets .NET 10 through the SDK for console, library, Windows Forms and WPF projects. .NET Framework 4.8.1 is maintenance-only: it still works, and Visual Studio 2026 still opens and builds its projects, but new work starts on .NET 10.

Install Visual Studio 2022, or Visual Studio 2019 because 2022 supposedly lacks Visual Basic web projects.

Visual Studio 2026 is the current IDE and has the VB templates. Visual Studio still offers "ASP.NET Web Application (.NET Framework)" for Visual Basic; only ASP.NET Core has no Visual Basic support. The web options are on Web, HTTP and Services.

Mono (or its vbnc compiler) is a way to compile Visual Basic on Linux and macOS.

The dotnet SDK compiles Visual Basic on Windows, Linux and macOS with Microsoft’s Roslyn compiler. Mono’s vbnc is no longer maintained and is not needed.

Newer .NET versions bring new Visual Basic features.

The language has had no new syntax since Visual Basic 16.9. Versions 17.0 and 17.13 only recognize attributes and constraints from newer .NET or C# code (see History, Versions and Language Strategy).

The first program is a Windows Forms click handler or a console module, and nothing says that the project templates leave Option Strict off.

The default is Option Strict Off. Turn it on in the project file, as in this page, before you write the second line of code.

Installing a very old Visual Basic (version 6) from an archive or a download site.

Not covered, and never a recommendation: the Visual Basic 6 IDE has been unsupported since 2008, and downloads of it from unofficial sites are a risk. The legacy dialects are on The VB Family: VB6, VBA and VBScript.

Common first-day problems

Symptom Cause and fix

dotnet new console creates a .cs file

The default language is C#. Add -lang VB (or -lang "VB").

dotnet is not recognized, or shows an old SDK

The SDK is not on the PATH, or global.json pins another version. Run dotnet --list-sdks and dotnet --info.

BC30512 on a line that looks harmless

The project has Option Strict On and the line mixes text and numbers or narrows a type. Convert explicitly.

Types appear in Shelf.Core.Shelf.Core

A Namespace Shelf.Core block inside a project whose RootNamespace is already Shelf.Core. Remove the block, or change the RootNamespace.

The application opens a console window when it should be a window, or the reverse

Wrong OutputType: WinExe for a graphical application, Exe for a console one.

BC30689 on the first line of the program

Statements outside a Sub, Function or Module. VB has no top-level statements.

The solution does not build on Linux or macOS because of Windows Forms or WPF

Those projects need net10.0-windows, and building them off Windows needs EnableWindowsTargeting set to true. Running them needs Windows.

An edit in Visual Studio Code shows no errors, yet the build fails

Visual Basic has no language server in Visual Studio Code. The BC errors only appear in dotnet build.

NuGet reports a vulnerability warning for a package of the template

Package audit messages (NU1903 and similar) come from NuGet, not from Visual Basic. Update the package, or see the notes on Projects, MSBuild and the dotnet CLI about NuGetAudit.

Where to go next

Read the pages in this order for a first pass: Visual Basic and .NET (what you can build), Program Structure and Code Conventions, Option Statements, Data Types and Literals, Control Flow and Procedures: Sub and Function. A reader coming from C# or Java should read Visual Basic for Programmers of Other Languages right after this page. For the .NET platform itself, the C# reference has C# and .NET and Build and Tooling, which apply to Visual Basic unchanged.