C# & .NET (C# 14, .NET 10 LTS) Module 1 – Start here: C#, .NET and your first programs
What C# and .NET are, and which version to use
How the C# compiler, the .NET runtime and its libraries turn a source file into a running program, how long each .NET is supported, and which to choose.
What you will learn
- Explain how the C# compiler, the .NET runtime and its libraries turn a source file into a running program
- Identify the runtime and the C# language version that a program or project uses
- Compare LTS and STS releases by their support, and plan the move off .NET 8 and .NET 9
- Choose between .NET 10, .NET 11 and .NET Framework 4.8.1 for a new project
What you’ll learn
What you will learn
- Explain how the C# compiler, the .NET runtime and its libraries turn a source file into a running program
- Identify the runtime and the C# language version that a program or project uses
- Compare LTS and STS releases by their support, and plan the move off .NET 8 and .NET 9
- Choose between .NET 10, .NET 11 and .NET Framework 4.8.1 for a new project
On this page
A C# program never runs by itself: a compiler turns it into intermediate code, a runtime turns that into machine code,
and a set of libraries does the everyday work behind lines such as Console.WriteLine. Together they are .NET, which
ships a new major version every November with either two or three years of support, so the version you build on
decides how long your program keeps getting security fixes.
This lesson takes a real program apart to show each piece, asks the compiler which C# version a project gets and reads the release index that Microsoft publishes to see which versions are supported. For most new code the answer is .NET 10, the LTS release: A long-term support release of .NET: an even-numbered version, such as .NET 8 or .NET 10, with three years of free fixes from its release., unless the program needs a Windows technology that only .NET Framework still has.
Your C# becomes IL, and the runtime turns IL into machine code
Here is a small program that asks .NET about itself: which runtime is running it, on which platform, whether code is being compiled while it runs, and which file each of four everyday types comes from. Read the output before the explanation:
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text.Json;
// What runs this program, and which library assemblies its types come from.
Console.WriteLine($"Runtime: {RuntimeInformation.FrameworkDescription}");
Console.WriteLine($"Platform: {RuntimeInformation.RuntimeIdentifier}");
Console.WriteLine($"JIT compiling: {RuntimeFeature.IsDynamicCodeCompiled}");
Console.WriteLine($"Program file: {Assembly.GetEntryAssembly()!.GetName().Name}.dll");
Console.WriteLine();
(string Name, Type Type)[] used =
[
("Console", typeof(Console)),
("List<T>", typeof(List<>)),
("Enumerable", typeof(Enumerable)),
("JsonSerializer", typeof(JsonSerializer)),
];
foreach ((string name, Type type) in used)
{
Console.WriteLine($"{name,-15} is in {type.Assembly.GetName().Name}.dll");
} Output
Runtime: .NET 10.0.12 Platform: osx-arm64 JIT compiling: True Program file: app.dll Console is in System.Console.dll List<T> is in System.Private.CoreLib.dll Enumerable is in System.Linq.dll JsonSerializer is in System.Text.Json.dll
Recorded with .NET SDK 10.0.401 (runtime 10.0.12) on macOS 26 arm64. To run it yourself: dotnet run app.cs
Four facts are in that output. The runtime is .NET 10.0.12 on osx-arm64, a Mac with an Arm processor. Code is
compiled while the program runs. The program itself is a file called app.dll, although you wrote app.cs. And the
types it used come from four other .dll files, from System.Console.dll to System.Text.Json.dll.
Each fact belongs to one piece of .NET. The C# compiler, Roslyn, reads your source and writes
IL: Intermediate language: the processor-independent instructions that the C# compiler writes into an assembly. The .NET runtime compiles them into machine code before they run., intermediate language, into an assembly: A .dll or .exe file of compiled .NET code: the IL of its methods, metadata that names its types and members, and any resources. It is the unit that .NET loads, versions and references.: the app.dll above,
which holds the IL of every method and the metadata that names every type. IL is the same on every operating system,
so the runtime finishes the job: it loads the assembly and the library assemblies it needs, and its
JIT compiler: The just-in-time compiler of the .NET runtime: it compiles the IL of a method into machine code for the processor it runs on, just before the method first runs. turns each method’s IL into machine code just before the method first
runs. Step through the trip:
The drawing shows the whole scene; its 7 steps are listed below.
Every step as text
- You write C#. app.cs holds C# as text. People can read it; no processor can run it as it is.
- The compiler checks it. dotnet run hands app.cs to the C# compiler, Roslyn, which ships in the .NET SDK. It checks the code against the C# version of the project and reports every error it finds; with an error, no app.dll is written.
- IL in an assembly. The compiler writes app.dll, an assembly: intermediate language (IL) for every method, and metadata that names every type and member. The same app.dll works on Windows, macOS and Linux.
- The runtime loads it. The .NET runtime loads app.dll and the library assemblies it uses: System.Console.dll for Console, System.Private.CoreLib.dll for List<T>, System.Linq.dll and System.Text.Json.dll, as the program printed.
- Just in time. Just before a method of app.dll runs for the first time, the JIT compiler turns its IL into machine code for this processor, Arm64 on the Mac that ran the program. That is why it printed JIT compiling: True.
- The processor runs it. The processor runs the machine code, and later calls reuse it. A method that is called often is compiled once more in the background, with full optimisation: .NET calls this tiered compilation.
- Or ahead of time. Native AOT takes the other path: dotnet publish compiles all the IL to machine code ahead of time, into one executable that needs neither an installed runtime nor a JIT. It starts faster, but code that generates code at run time cannot work there.
The libraries are the base class library: The standard libraries that come with .NET, such as System.Console and System.Collections.Generic: thousands of ready-made types that every .NET program can use.: thousands of ready-made types, from
Console to List<T> and JsonSerializer, which come with .NET. What you install to build programs is the
.NET SDK: What you install to build .NET programs: the dotnet command with the C# compiler, MSBuild, NuGet, project templates and a matching runtime., and it holds everything above:
| Piece | What it is | Where this program met it |
|---|---|---|
| C# | The language, the rules your source follows | app.cs |
| Compiler | Roslyn, which turns C# into IL | app.dll, written for you by dotnet run |
| Runtime | CoreCLR, which loads assemblies, compiles IL and frees memory | Runtime: .NET 10.0.12 |
| Libraries | The base class library and the other assemblies of .NET | System.Console.dll and the rest |
| SDK | The dotnet command with the compiler, MSBuild, NuGet and a runtime |
what you install in the next lesson |
There is one exception to “compiled while it runs”: Native AOT: Ahead-of-time publishing: dotnet publish compiles a whole app into one native executable that needs no installed .NET runtime and no JIT, at the cost of run-time code generation and dynamic loading. publishing compiles all the IL ahead of time into one executable that needs no installed runtime, and starts faster for it. The cost, in Microsoft’s list of its limits, is that such a program cannot load assemblies or generate code while it runs.
Calling C# interpreted
Nothing in that trip interprets your code line by line: every method is compiled to machine code before it runs, either just in time or, with Native AOT, ahead of time. A slow first call is the JIT compiling that method, not a slow interpreter.
Checkpoint
Check: From C# to machine code
Each .NET version sets the C# version your project gets
C# and .NET have separate version numbers that move together. A project names its
target framework: The version of .NET a project is built for, written as a short name such as net10.0. It decides which library types are available and the project's default C# version., such as net10.0, and the compiler picks the newest C# that
the framework supports. You can ask the compiler what it chose: the directive #error version makes it stop with an
error that reports its own version and the project’s language version. This session builds a two-file project whose
only line of code is that directive:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
</Project> from session import run
# A project whose only source line is #error version: the C# compiler reports its own version and the language
# version this project gets, then the build fails, as #error always makes it fail.
run("""
cd version
dotnet --version
!dotnet build -v q
""") Output
$ cd version
$ dotnet --version
10.0.401
$ dotnet build -v q
version/Program.cs(1,8): error CS1029: #error: 'version' [version/version.csproj]
version/Program.cs(1,8): error CS8304: Compiler version: '5.9.0-1.26423.113 (e34a38d2ae1fc26406a317517196e55c68ff83ab)'. Language version: 14.0. Compiler path: '…/dotnet-root/sdk/10.0.401/Roslyn/bincore/Microsoft.CodeAnalysis.CSharp.dll'. [version/version.csproj]
Build FAILED.
version/Program.cs(1,8): error CS1029: #error: 'version' [version/version.csproj]
version/Program.cs(1,8): error CS8304: Compiler version: '5.9.0-1.26423.113 (e34a38d2ae1fc26406a317517196e55c68ff83ab)'. Language version: 14.0. Compiler path: '…/dotnet-root/sdk/10.0.401/Roslyn/bincore/Microsoft.CodeAnalysis.CSharp.dll'. [version/version.csproj]
0 Warning(s)
2 Error(s)
Time Elapsed …
[exit status 1]
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 version_session.py
The build fails on purpose, and the second error, CS8304, carries the answer: compiler 5.9.0, which is the Roslyn of
SDK 10.0.401, and Language version: 14.0 for a net10.0 project. MSBuild then repeats both errors in its summary.
The same compiler gives an older target framework an older C# by default:
| Target framework | Default C# version |
|---|---|
net11.0 (.NET 11) |
C# 15 |
net10.0 (.NET 10) |
C# 14 |
net9.0 (.NET 9) |
C# 13 |
net8.0 (.NET 8) |
C# 12 |
netstandard2.1 |
C# 8.0 |
| .NET Framework, every version | C# 7.3 |
The default follows the libraries: a language feature can need types that only a newer runtime has. The C# language
reference calls a version newer than the target’s default unsupported, and warns that raising LangVersion in an
older project can cause errors that are hard to diagnose, at compile time and at run time.
Unity has a C# version of its own
Unity compiles your scripts with its own copy of Roslyn. The Unity 6.6 manual sets the language level at C# 9.0 and lists the C# 9 features it does not support, so code written for this track’s C# 14 may need changes there. The module for Unity developers covers what carries over.
Checkpoint
Check: The C# version a project gets
LTS releases get three years of fixes, STS releases get two
A new major version of .NET comes out every November. Even-numbered versions are long-term support (LTS) releases, with three years of fixes; odd-numbered versions are STS release: A standard-term support release of .NET: an odd-numbered version, such as .NET 9 or .NET 11, with two years of free fixes from its release. (STS) releases, with two. Microsoft’s support policy says the quality of the two kinds is the same and only the length of support differs. Walk through the releases from .NET 5 on:
- .NET 5
One .NET after .NET Core 3.1 STS
.NET 5 came out in 2020 and dropped "Core" from the name. As a short-term release it was supported for 18 months. Its projects default to C# 9.
- .NET 6
Long-term support, three years LTS
.NET 6 came out in 2021 as an LTS release, with three years of fixes, and defaults to C# 10. Its support has ended.
- .NET 7
Short-term, 18 months STS
.NET 7 came out in 2022 and defaults to C# 11. Short-term releases then had 18 months of support, so it ended before .NET 6 did.
- .NET 8
Long-term support, three years LTS
.NET 8 came out in 2023 as an LTS release and defaults to C# 12. Its three years end on the same day as the support of .NET 9.
- .NET 9
Short-term, now two years STS
.NET 9 came out in 2024 and defaults to C# 13. Microsoft lengthened short-term support to two years, which makes .NET 9 end on the same day as .NET 8.
- .NET 10
Long-term support, three years LTS
.NET 10 came out in 2025 as an LTS release, with three years of fixes, and defaults to C# 14. This track uses it.
- .NET 11
The next short-term release STS
.NET 11 is the release of 2026 and defaults to C# 15. Like every release it comes first as previews and release candidates; a go-live release candidate is supported in production. As an STS release it gets two years, which end in 2028, the year the support of .NET 10 ends too.
The timeline has 7 events, from .NET 5 to .NET 11.
Within its support, a release gets a patch almost every month, on the second Tuesday when it carries security fixes, and only a system on the latest patch counts as supported. The last six months are the maintenance phase, in which a release gets security fixes only. After its end of support it gets nothing.
Microsoft also publishes these facts as data, a release index in JSON with one entry per version. This program reads
a saved copy of it, releases-index.json in the same folder, and prints every version that is still in support:
using System.Text.Json;
// releases-index.json is a saved copy of the release index that Microsoft publishes for .NET, so the program
// reads the same data on every run, with no network.
using JsonDocument index = JsonDocument.Parse(File.ReadAllText("releases-index.json"));
var supported = new List<(string Version, string Type, string Phase, string Sdk, string End)>();
var outOfSupport = new List<string>();
foreach (JsonElement channel in index.RootElement.GetProperty("releases-index").EnumerateArray())
{
string version = channel.GetProperty("channel-version").GetString()!;
string phase = channel.GetProperty("support-phase").GetString()!;
if (phase == "eol")
{
outOfSupport.Add(version);
continue;
}
string end = channel.TryGetProperty("eol-date", out JsonElement eol) ? eol.GetString()! : "not set yet";
supported.Add((version, channel.GetProperty("release-type").GetString()!.ToUpperInvariant(), phase, channel.GetProperty("latest-sdk").GetString()!, end));
}
Console.WriteLine($"{"Version",-8} {"Type",-5} {"Phase",-12} {"Newest SDK",-24} End of support");
foreach (var c in supported)
{
Console.WriteLine($"{c.Version,-8} {c.Type,-5} {c.Phase,-12} {c.Sdk,-24} {c.End}");
}
Console.WriteLine($"Out of support: {string.Join(", ", outOfSupport)}");
foreach (var day in supported.Where(c => c.End != "not set yet").GroupBy(c => c.End).Where(g => g.Count() > 1))
{
Console.WriteLine($"Ending together on {day.Key}: {string.Join(" and ", day.Select(c => c.Version))}");
}
var newestLts = supported.First(c => c.Type == "LTS" && c.Phase == "active");
Console.WriteLine($"For new work: {newestLts.Version}, the newest LTS channel in its active phase"); Output
Version Type Phase Newest SDK End of support 11.0 STS go-live 11.0.100-rc.2.26504.105 not set yet 10.0 LTS active 10.0.402 2028-11-14 9.0 STS maintenance 9.0.319 2026-11-10 8.0 LTS maintenance 8.0.426 2026-11-10 Out of support: 7.0, 6.0, 5.0, 3.1, 3.0, 2.1, 2.2, 2.0, 1.1, 1.0 Ending together on 2026-11-10: 9.0 and 8.0 For new work: 10.0, the newest LTS channel in its active phase
Recorded with .NET SDK 10.0.401 (runtime 10.0.12) on macOS 26 arm64. To run it yourself: dotnet run app.cs
The saved index lists four versions in support and ten out of it. .NET 10 is the LTS release in its active phase, the
choice the program prints for new work. .NET 11 has no end date yet, because it was still a release candidate,
supported in production (go-live). And .NET 8 and .NET 9 are both in maintenance and end on the same day, the date
in the last column. That date is the deadline for every program on either of them: plan the move to .NET 10, the
supported LTS release, well before it.
Key idea
An LTS release gets three years of fixes and an STS release two, counted from their November release; only the latest patch is supported, and a release’s last six months bring security fixes only.
Checkpoint
Check: LTS, STS and patches
For new code choose .NET 10, unless an old Windows technology ties you down
There is one more .NET. .NET Framework, the original Windows-only implementation, is at version 4.8.1, and the lifecycle FAQ defines it as a component of Windows, supported for as long as the Windows version it is installed on. Microsoft’s introduction to .NET calls it supported and in maintenance, while the modern .NET is the one that evolves, and its projects default to C# 7.3. Some of its technologies never came to the modern .NET: Microsoft lists AppDomains, .NET Remoting and Workflow Foundation among those unavailable on .NET 6 and later. A program that depends on them stays on .NET Framework until it is rewritten; everything else is better started on .NET.
Between the modern releases the choice is about maturity more than about support. .NET 10 is the LTS release, final and patched almost every month, with three years of fixes from its release in 2025. .NET 11 brings C# 15, but in the saved index it is still a release candidate, and as an STS release it gets two years from its release in 2026. Both therefore end in 2028, just as .NET 8 and .NET 9 end together: a project started now has about two years on either, and then moves to .NET 12, the next LTS release, which comes a year after .NET 11. Microsoft’s guidance is the newest release, LTS or STS, for a service that the team keeps updating, and an LTS release for software that others install and keep. Answer the three questions in the table for your own project:
Answer the questions above: the table then marks what fits your case and says why the rest does not.
| Target | Support | Language and libraries | Runs on | Older Windows technologies |
|---|---|---|---|---|
| .NET 10 (LTS) Default C# version: C# 14 | Good three years from its release in 2025, until 2028; final, with monthly patches | Good C# 14 and the newest libraries of an LTS release | Good Windows, macOS and Linux, on x64 and Arm64 | Poor no AppDomains, .NET Remoting or Workflow Foundation |
| .NET 11 (STS) Default C# version: C# 15 | Mixed two years from its release in 2026, also until 2028; a release candidate in the saved index | Good C# 15, the newest language | Good Windows, macOS and Linux, on x64 and Arm64 | Poor no AppDomains, .NET Remoting or Workflow Foundation |
| .NET Framework 4.8.1 Default C# version: C# 7.3 | Mixed supported with its Windows version; in maintenance while .NET evolves | Poor C# 7.3 by default; newer C# is unsupported | Poor Windows only | Good AppDomains, .NET Remoting and Workflow Foundation all work |
How the answers decide
- “Must the program run on macOS or Linux, now or later?” Yes: rules out .NET Framework 4.8.1. .NET Framework is part of Windows and runs nowhere else.
- “Does it depend on AppDomains, .NET Remoting or Workflow Foundation?” Yes: rules out .NET 10 (LTS) and .NET 11 (STS). Microsoft lists AppDomains, .NET Remoting and Workflow Foundation as unavailable on .NET 6 and later, so only .NET Framework still runs such code.
- “Does it depend on AppDomains, .NET Remoting or Workflow Foundation?” Yes: adds a caveat to .NET Framework 4.8.1. It works, but .NET Framework is in maintenance while .NET evolves: plan the move away from those technologies.
- “Does it depend on AppDomains, .NET Remoting or Workflow Foundation?” No: rules out .NET Framework 4.8.1. Without those technologies nothing ties new code to .NET Framework, whose projects default to C# 7.3 and which gains no new features.
- “Is it a service that your team keeps updating, or software that others install and keep?” Software others install and keep: adds a caveat to .NET 11 (STS). For software that people install and keep, Microsoft's guidance points to an LTS release; .NET 11 is an STS release, and a release candidate in the saved index.
- “Is it a service that your team keeps updating, or software that others install and keep?” A service we keep updating: For a service that is updated regularly, Microsoft's guidance is the newest release, LTS or STS. Both modern targets are supported until 2028.
In short: start new code on .NET 10, the final LTS release, or on .NET 11 for a service that the team updates every year; plan the move to .NET 12 before 2028 either way; and keep .NET Framework 4.8.1 only for code that needs a technology .NET dropped.
Read the release index yourself
The live index is a JSON file at dotnetcli.blob.core.windows.net/dotnet/release-metadata/releases-index.json.
Paste it into a JSON viewer, find the entry for your version and read its support-phase and eol-date.
Checkpoint
Check: Choosing a .NET for new code
Practise: from source to support
Each question below checks one idea of this lesson, starting with the one you have practised least, and every answer comes with the reason it is right or wrong:
Practice that adapts to you
Practise this lesson
11 questions about 4 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.
Ask your own SDK
Once the next lesson has installed the SDK, copy inside/app.cs into an empty folder and run dotnet run app.cs.
Compare the runtime and platform lines with the ones above: on Windows the platform reads win-x64 or win-arm64.
Interview questions
Fresher · What is the difference between .NET and .NET Framework?
.NET Framework is the original implementation of .NET. It runs only on Windows, is at version 4.8.1 and is supported as part of the Windows version it is installed on, in maintenance. .NET, called .NET Core until version 5, is the modern implementation: it runs on Windows, macOS and Linux, ships a new major version every November and is the one that evolves. Both run C# and share much of the base class library, so most code moves between them, but .NET Framework projects default to C# 7.3 while .NET 10 projects get C# 14, and some technologies, such as AppDomains, .NET Remoting and Workflow Foundation, exist only in .NET Framework. New code goes on .NET; .NET Framework is for programs that need what only it has.
Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.
-
Mid to senior
Your team runs three services on .NET 8 and one on .NET 9, and the support of both ends on the same day. Plan the upgrade: which version do you move them to, what do you check first, and how do you keep the change safe?
-
Fresher to mid
A colleague says C# programs start slowly because the .NET runtime interprets them. Explain what really happens between the source file and the processor, and when you would publish with Native AOT instead.
Key takeaways
- The C# compiler turns your source into IL in an assembly, and the .NET runtime’s JIT compiles that IL into machine code just before each method first runs; Native AOT does the compiling at publish time instead.
- The base class library is the set of assemblies that comes with .NET, and the SDK is what you install to build: the
dotnetcommand, the compiler, MSBuild, NuGet and a runtime. - A project’s target framework sets its default C# version, C# 14 for
net10.0, and#error versionmakes the compiler report both its version and the language version. - LTS releases get three years of fixes and STS releases two; only the latest monthly patch is supported, and .NET 8 and .NET 9 end on the same day, so programs on them move to .NET 10.
- New projects start on .NET 10, or on .NET 11 for a service updated every year; both are supported until 2028, and .NET Framework 4.8.1 stays only for technologies that .NET dropped.
Terms in this lesson
- .NET SDK
- What you install to build .NET programs: the dotnet command with the C# compiler, MSBuild, NuGet, project templates and a matching runtime.
- assembly
- A .dll or .exe file of compiled .NET code: the IL of its methods, metadata that names its types and members, and any resources. It is the unit that .NET loads, versions and references.
- base class library
- The standard libraries that come with .NET, such as System.Console and System.Collections.Generic: thousands of ready-made types that every .NET program can use.
- IL
- Intermediate language: the processor-independent instructions that the C# compiler writes into an assembly. The .NET runtime compiles them into machine code before they run.
- JIT compiler
- The just-in-time compiler of the .NET runtime: it compiles the IL of a method into machine code for the processor it runs on, just before the method first runs.
- LTS release
- A long-term support release of .NET: an even-numbered version, such as .NET 8 or .NET 10, with three years of free fixes from its release.
- Native AOT
- Ahead-of-time publishing: dotnet publish compiles a whole app into one native executable that needs no installed .NET runtime and no JIT, at the cost of run-time code generation and dynamic loading.
- STS release
- A standard-term support release of .NET: an odd-numbered version, such as .NET 9 or .NET 11, with two years of free fixes from its release.
- target framework
- The version of .NET a project is built for, written as a short name such as net10.0. It decides which library types are available and the project's default C# version.
References
- Introduction to .NET (Microsoft Learn)
- .NET releases, patches, and support (Microsoft Learn)
- .NET and .NET Core Support Policy (Microsoft (.NET))
- .NET release index (releases-index.json) (Microsoft (.NET))
- C# language versioning (Microsoft Learn)
- Native AOT deployment overview (Microsoft Learn)
- Compilation config settings (tiered compilation) (Microsoft Learn)
- Lifecycle FAQ, .NET Framework (Microsoft Learn)
- .NET Framework technologies unavailable on .NET 6+ (Microsoft Learn)
- Unity Manual: C# compiler (Unity Technologies)
Related tools
Report a problem with this lesson
Kept only in this browser. Your Learn progress