Install .NET SDK on Windows and run your first program
The installer asks you nothing and takes a few minutes. The time goes into checking that the version answering your terminal is the one you think it is.
Two commands need to work at the end. dotnet --info should answer with a version
number, and dotnet run should print a line of text to the console. To install
.NET SDK you download one file and click through it. The interesting part starts
after that.
Step 0: check whether you already have it
Open PowerShell and type this before downloading anything:
dotnet --list-sdks
A line with a number and a path means the SDK is already there:
10.0.400 [C:\Program Files\dotnet\sdk]
If it’s there, stop. Skip ahead to the first program. Visual Studio, Rider and a handful of other tools pull an SDK in as part of their own setup, so that line shows up more often than anyone’s memory of what they installed last year would suggest. Empty output, or a complaint about an unrecognised command, means you carry on.
The check is worth the ten seconds because a second install alongside the first one doesn’t fail. It succeeds, leaves you with two copies, one of which happens to come first in PATH, and a week of wondering why your editor disagrees with your terminal.
Run the installer, then read what it gives you
The Windows x64 installer comes from the .NET download page. It’s around 200 MB and asks nothing beyond permission to install. There’s no component picker and no install location to choose. Nothing to get wrong. You install .NET SDK once per machine and then mostly stop thinking about it.
Close your terminal afterwards and open a new one. Then:
dotnet --info
The reply is long, and that’s the point of it. It carries everything you’d otherwise have to ask for one question at a time, and it’s the first thing anyone willing to help will want pasted into the thread.
Three different version numbers, none of them wrong
That single reply reports several versions, and they aren’t one number written out in a few places:
.NET SDK:
Version: 10.0.400
Commit: 14fbf8d527
MSBuild version: 18.9.6+14fbf8d52
Runtime Environment:
RID: win-x64
Base Path: C:\Program Files\dotnet\sdk\10.0.400\
Host:
Version: 10.0.11
Architecture: x64
The number under SDK and the one under Host differ, and they’re supposed to.
The first describes the tools you compile with. The second describes the runtime
that executes whatever those tools produced. The SDK moves faster, because changes
to the compiler and the project templates don’t require touching the thing that
runs compiled code.
A separate command shows how many runtimes are sitting side by side:
dotnet --list-runtimes
On this machine it prints these two among others:
Microsoft.NETCore.App 9.0.19 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 10.0.11 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Two entries from the same family, one from .NET 9 and one from .NET 10. The older one is left over from a previous SDK, and it earns its place, because a program built against .NET 9 still looks for it at startup. You come back to this list when a program runs for you and not for someone else. Deleting old runtimes speeds up nothing. They cost disk space and nothing else.
Further down, dotnet --info prints this on some machines:
Other architectures found:
x86 [C:\Program Files (x86)\dotnet]
That’s a second install in a different architecture, usually left behind by some
other installer. It’s harmless on its own. What matters is that where dotnet points at the
folder without (x86) in its name. If it points at the (x86) one, your PATH order is backwards
and this is the moment to fix it.
Your first program takes two commands
One command scaffolds a console project:
dotnet new console -o hello
cd hello
dotnet run
The first prints what it did:
The template "Console App" was created successfully.
Processing post-creation actions...
Restoring C:\...\hello\hello.csproj:
Determining projects to restore...
Restored C:\...\hello\hello.csproj (in 118 ms).
Restore succeeded.
Those last lines mean the package restore already happened. A separate
dotnet restore isn’t needed, though plenty of tutorials tell
you to run one immediately after creating a project.
Two files appear. hello.csproj describes the project and Program.cs holds the
code, which starts life as a single line:
Console.WriteLine("Hello, World!");
There’s no class, no Main method and no declaration wrapped around it. The
compiler supplies those at build time and the file stays at one statement. Older
tutorials show a dozen lines here, which isn’t an error on their part, just the
previous template convention.
The obj folder that turns up beside them comes from the restore and isn’t part
of your code. Inside hello.csproj, one line matters:
<TargetFramework>net10.0</TargetFramework>
It decides which version of the platform your program gets built against, and
it’s what you edit when moving a project to a different one. That number doesn’t
have to match your SDK version. It has to match one of the runtimes from
dotnet --list-runtimes.
The first dotnet run on a clean machine took 6.5 seconds here. The second, with
no code changes, took 2.5. The gap is compilation, which runs in full the first
time and then drops out until you touch a file again. So the first run can look frozen. It isn’t.
The very first dotnet command on a fresh system adds one more thing. It prints a
greeting, a note about telemetry collection, and a line about a certificate:
Installed an ASP.NET Core HTTPS development certificate.
To trust the certificate, run 'dotnet dev-certs https --trust'
That certificate matters later, the first time you open an https address from a
web project. You’ll see this once.
The two failures you’ll actually hit
The common one arrives after a perfectly good install:
'dotnet' is not recognized as an internal or external command,
operable program or batch file.
PowerShell words the same absence differently:
The term 'dotnet' is not recognized as the name of a cmdlet, function, script
file, or operable program.
This comes from the shell rather than from .NET, so it arrives in your Windows
display language. The cause is nearly always the same one. The installer appended
C:\Program Files\dotnet\ to PATH, but a terminal you opened earlier read the old
copy of that variable at startup and nothing will make it read again. Close the
window, open a new one, and confirm with where dotnet. The right answer is
C:\Program Files\dotnet\dotnet.exe. Rebooting gets recommended a lot in forum
answers and is almost never what fixes this.
The second failure is more interesting, because it only shows up in one directory. The same command works a level above and stops working once you step into the project:
* You intended to execute a .NET SDK command:
A compatible .NET SDK was not found.
Requested SDK version: 9.0.100
global.json file: C:\...\global.json
Installed SDKs:
10.0.400 [C:\Program Files\dotnet\sdk]
Install the [9.0.100] .NET SDK or update global.json to match an installed SDK.
A global.json file is pinning the project to one SDK version. Course
repositories and company templates carry them often, and since the file sits in
the project root and runs to a few lines, it’s easy to miss when you clone someone
else’s code. You can install the version it asks for, or raise the number in the
file to whatever dotnet --list-sdks reports. SDK versions coexist without
conflict, so installing another one breaks nothing that already works.
Installing the SDK is done when dotnet --info and dotnet run both answer with
what you expect. The next message you see will come from the compiler, and the
most common of those is
CS0029 on an assignment.
DevJourney runs these same commands inside the app, against real dotnet, with nothing to configure separately.