The dotnet CLI workflow
Solution and project scaffolding, package management, and the build, test, watch and format loop you actually live in.
Scaffolding a solution
A solution (.sln) is a grouping file for related projects — it is not required to build anything, but it gives the CLI and every editor one entry point. The usual shape is one solution containing an app project, a test project and one or more libraries.
dotnet new sln -n Shop
dotnet new classlib -n Shop.Core -o src/Shop.Core
dotnet new webapi -n Shop.Api -o src/Shop.Api -f net8.0
dotnet new xunit -n Shop.Tests -o tests/Shop.Tests
dotnet sln add src/Shop.Core src/Shop.Api tests/Shop.Tests
dotnet add src/Shop.Api reference src/Shop.Core
dotnet add tests/Shop.Tests reference src/Shop.Core-nnames the output,-osets the folder,-fpins the target framework.dotnet new listshows every installed template;dotnet new installadds community ones.- Keep tests in a sibling
tests/folder and reference projects with relative paths so the layout survives a move.
Packages, restore and lock files
Package commands edit the project file for you, which is why the CLI is worth learning even if you normally work in an IDE.
dotnet add src/Shop.Api package Microsoft.EntityFrameworkCore.Sqlite
dotnet add src/Shop.Api package Microsoft.EntityFrameworkCore.Sqlite --version 8.0.11
dotnet remove src/Shop.Api package Newtonsoft.Json
dotnet list package # direct dependencies
dotnet list package --outdated # newer versions available
dotnet list package --vulnerable # known CVEs in the graph
dotnet restore # download everything up front| Artifact | Purpose |
|---|---|
obj/project.assets.json | The resolved dependency graph MSBuild reads during a build |
packages.lock.json | Optional lock file making restores reproducible; enable with RestorePackagesWithLockFile |
~/nuget/packages | The global package cache shared by every project on the machine |
NuGet.config | Which feeds a repository may restore from |
Commit the lock file for applications so CI restores the exact graph that passed review. For a library the lock file adds friction for consumers and is usually left out.
The inner loop
dotnet build # Debug
dotnet build -c Release # optimised, warnings still checked
dotnet build --no-restore # skip restore when nothing changed
dotnet run --project src/Shop.Api
dotnet run --project src/Shop.Api -- --port 5001 # args after -- reach the app
dotnet test # discover and run every test project
dotnet test --filter "FullyQualifiedName~Cart" # narrow to one class
dotnet watch run --project src/Shop.Api # hot reload on file save
dotnet format # apply the repo .editorconfig rulesdotnet watchrebuilds and restarts on save; edits to method bodies reload without restarting when the runtime supports it.dotnet format --verify-no-changesis the CI-safe form: it exits non-zero instead of rewriting files.--no-restoreand--no-buildmatter in pipelines where a previous step already did the work.- Build output lands in
bin/<config>/<tfm>/; never commitbinorobj.
💡
Run
dotnet build -c Release locally before opening a pull request. Some analyser warnings are only reported in Release, and the CI configuration you forgot to test is exactly the configuration that breaks.FAQ
What do I commit to source control?
Source, project files,
global.json, Directory.Build.props, .editorconfig and the app lock file. Add a .gitignore that excludes bin/, obj/, .vs/ and *.user.Build or publish?
build produces assemblies for development and testing. publish produces a deployable layout: dependencies resolved, runtime configuration applied, ready to copy to a host.Related
.NET SDK and project files Configuration and logging
Last refreshed 2026-09-18.