Setting up .NET: SDK, CLI and project layout

Install the SDK, create and run projects from the CLI, understand target frameworks, and know what each command in the loop does.

The SDK and the command loop

The .NET SDK contains the runtime, the compilers and the CLI. One installation can build and run for several target frameworks, so you rarely need more than one SDK version installed locally.

dotnet --version              # the SDK in use
dotnet --list-sdks
dotnet --list-runtimes
dotnet --info                 # everything, including the RID and base path

dotnet new console -o Hello
cd Hello
dotnet run                    # restore, build and run in one step
dotnet build -c Release
dotnet publish -c Release -r linux-x64 --self-contained false -o out
dotnet test
dotnet format                 # apply the standard style and analysers
CommandWhat it doesWhen you need it
dotnet new <template>Scaffolds a project from a templateStarting anything new
dotnet restoreDownloads NuGet packages listed in the projectCI, or after editing the project file
dotnet buildCompiles without runningChecking compile errors in CI
dotnet runBuilds and runs the startup projectLocal development
dotnet publishProduces a deployable output directoryShipping
dotnet testDiscovers and runs test projectsAny test run
dotnet watchRebuilds and restarts on file changeIterating on a service or app

global.json pins the SDK version for a repository, which is how you stop a machine with a newer SDK from producing a subtly different build. It belongs in version control next to the solution file.

Solutions, projects and target frameworks

<!-- App.csproj — the SDK-style project file -->
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net10.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <LangVersion>latest</LangVersion>
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
    <InvariantGlobalization>true</InvariantGlobalization>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.0" />
    <ProjectReference Include="../Core/Core.csproj" />
  </ItemGroup>

</Project>
dotnet new sln -n Shop
dotnet new classlib -o Shop.Core
dotnet new web -o Shop.Api
dotnet sln add Shop.Core Shop.Api
dotnet add Shop.Api reference Shop.Core
dotnet add Shop.Api package Microsoft.EntityFrameworkCore.Sqlite

# multi-targeting: one library, two runtimes
# <TargetFrameworks>net8.0;net10.0</TargetFrameworks>
  • ImplicitUsings adds a standard set of using directives for the SDK in use; it is convenient and hides which namespace a type came from.
  • Nullable enable turns nullability into compile-time analysis. Treat the warnings as errors on new projects, or the annotations decay into noise.
  • InvariantGlobalization removes ICU data from the output and makes string comparison culture-independent. Enable it for containers and services; leave it off for user-facing formatting.
  • Directory.Build.props at the repository root applies settings to every project below it, which is the right place for warnings-as-errors and the language version.
<!-- Directory.Build.props — one place for settings shared by every project -->
<Project>
  <PropertyGroup>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
    <AnalysisLevel>latest-recommended</AnalysisLevel>
    <Deterministic>true</Deterministic>
  </PropertyGroup>
</Project>

File-based apps and running a snippet

# a single file with top-level statements and inline package directives
# hello.cs
# ---
# #!/usr/bin/env dotnet
# #:package [email protected]
# Console.WriteLine("Quick check".Humanize());
# ---
dotnet run hello.cs

# script-style execution without creating a project
dotnet tool install -g dotnet-script
dotnet script scratch.csx
💡
Use file-based apps for experiments and repro cases, and always create a real project for anything you intend to keep. The one-file form has no test project, no dependency pinning beyond the directive and no place to put a second class.

FAQ

What is the difference between the SDK and the runtime?
The runtime executes an already built application; the SDK adds the compiler, the CLI and the templates. A build machine or a development machine needs the SDK; a deployment target only needs the runtime, unless you publish self-contained.
Why does dotnet run rebuild every time?
It runs an implicit restore and build unless nothing changed. For a faster loop use dotnet watch, which keeps the build server warm, or run the built binary directly after a one-off dotnet build.

Syntax and types Dependency injection and configuration

Last refreshed 2026-09-18.