The project file
A .NET project is a folder with a project file, here App.csproj. It is XML for MSBuild, the .NET build engine. Sdk="Microsoft.NET.Sdk" brings in the standard build steps, and every .cs file in the folder is compiled.
App uses code it did not write. A ProjectReference points at another project, Greeter, built from its source. A PackageReference names a NuGet package, Newtonsoft.Json 13.0.3: someone else's library, downloaded ready-made.
Restore: NuGet packages
Packages must be on disk before a build. dotnet restore reads each PackageReference, asks the feed nuget.org, and unpacks the .nupkg (a zip file) into the global packages folder. dotnet build and dotnet run restore for you.
Version="13.0.3" means 13.0.3 or higher. NuGet picks the lowest version that fits, 13.0.3, even though 13.0.4 exists, so every machine restores the same thing. The result is saved in obj/project.assets.json.
One package holds builds for many frameworks: lib/net45, lib/netstandard2.0, lib/net6.0 and more. App targets net8.0. There is no lib/net8.0 folder, so NuGet takes the nearest compatible one: lib/net6.0.
Build and run
dotnet build runs MSBuild. It follows the ProjectReference: App needs Greeter, so Greeter is built first. The C# compiler turns Greeting.cs into Greeter.dll, in Greeter/bin/Debug/net8.0/.
Next the compiler turns Program.cs into App.dll, checked against Greeter.dll and Newtonsoft.Json.dll. MSBuild copies both into App/bin/Debug/net8.0/, beside App.dll, so the folder holds everything the app needs.
dotnet run builds if needed, then starts the app. The runtime loads App.dll, and loads Greeter.dll and Newtonsoft.Json.dll from the same folder when code first uses them. It prints {"Text":"Hello, NuGet!"}.
Rebuild and share
Edit Program.cs and build again. MSBuild compares inputs with outputs. Greeter.dll is newer than Greeting.cs, so Greeter's compile is skipped; only App is compiled. Large solutions rebuild much faster this way.
dotnet pack turns Greeter into Greeter.1.0.0.nupkg: a zip with Greeter.dll and a description. dotnet nuget push can upload it to a feed such as nuget.org. Then any project's PackageReference can restore it, just like Newtonsoft.Json.
What happens
// step 1/10 · project-file
App/App.csproj (the whole file)
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include=
"../Greeter/Greeter.csproj" />
<PackageReference
Include="Newtonsoft.Json"
Version="13.0.3" />
</ItemGroup>
</Project>
App/Program.cs compiled automatically (every **/*.cs)
The App.csproj card leaves out the PropertyGroup (OutputType Exe, TargetFramework net8.0) and the ItemGroup tags (the "…" lines); the step text shows the whole file. Splitting a tag over lines is ordinary XML. Skipping is per MSBuild target: the C# compile target (CoreCompile) runs only when an input file is newer than its outputs. Greeter is still visited but does no compiling. The .NET SDK also builds reference assemblies, so a change inside a Greeter method body may not even make App recompile.