dotnet CLI, Global Tools and Project Settings

The dotnet CLI is the primary tool for everything .NET โ€” creating projects, building, running, testing, publishing, managing packages, and running EF Core migrations. Beyond the basic commands, the CLI supports global tools (executables installed once per user, like dotnet-ef), and project-wide settings via Directory.Build.props and .editorconfig that keep multi-project solutions consistent without repeating configuration in every file. Mastering the CLI accelerates development and is essential for CI/CD pipelines where no IDE is available.

Essential dotnet CLI Commands

// โ”€โ”€ Project creation โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
dotnet new webapi    -n BlogApp.Api            // ASP.NET Core Web API
dotnet new classlib  -n BlogApp.Domain         // class library
dotnet new xunit     -n BlogApp.Tests          // xUnit test project
dotnet new console   -n BlogApp.Seeder         // console application
dotnet new gitignore                           // .gitignore for .NET
dotnet new editorconfig                        // .editorconfig template
dotnet new list                                // list all available templates

// โ”€โ”€ Building and running โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
dotnet build                                   // build (Debug by default)
dotnet build -c Release                        // build Release configuration
dotnet run   --project src/BlogApp.Api         // run the API
dotnet run   --project src/BlogApp.Api --watch // hot reload on file changes

// โ”€โ”€ Testing โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
dotnet test                                    // run all tests in solution
dotnet test --filter "Category=Unit"           // run tests matching a filter
dotnet test --coverage                         // collect code coverage
dotnet test -l "console;verbosity=detailed"    // verbose output

// โ”€โ”€ Publishing โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
dotnet publish -c Release -o ./publish         // publish to ./publish folder
dotnet publish -c Release --self-contained     // include .NET runtime
dotnet publish -c Release -r linux-x64         // publish for Linux x64
Note: dotnet run builds the project before running โ€” it is equivalent to dotnet build followed by running the output binary. For production use, always publish with dotnet publish -c Release and run the published output directly. The published artefact is a self-contained, optimised binary (or folder of DLLs) with all dependencies resolved. Running the development debug build in production is a common mistake that delivers lower performance and includes development-only middleware.
Tip: Install dotnet-ef as a global tool for EF Core migrations: dotnet tool install --global dotnet-ef. Then use it throughout development: dotnet ef migrations add InitialCreate --project src/BlogApp.Infrastructure --startup-project src/BlogApp.Api and dotnet ef database update --project src/BlogApp.Infrastructure --startup-project src/BlogApp.Api. The --startup-project flag points to the project that contains the appsettings.json with the connection string; --project points to the project that contains the DbContext and migrations.
Warning: dotnet watch run (hot reload) is convenient for development but should never be used in production. Hot reload patches the running process with changed code without a restart โ€” it works for most UI and API changes but has limitations: it does not support all code changes (constructor changes, type additions) and can leave the process in an inconsistent state if a reload fails. Always stop dotnet watch and use a clean dotnet publish + restart cycle for production deployments.

Directory.Build.props โ€” Shared MSBuild Properties

// Directory.Build.props โ€” place in solution root; applies to ALL projects
// Eliminates repetition of common settings across every .csproj

<!-- Directory.Build.props -->
<Project>
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
    <LangVersion>latest</LangVersion>
    <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
    <Authors>StackLesson</Authors>
    <Company>StackLesson Ltd</Company>
  </PropertyGroup>
</Project>

// Individual .csproj files become minimal โ€” only project-specific settings:
<Project Sdk="Microsoft.NET.Sdk">
  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore" />
  </ItemGroup>
</Project>

.editorconfig โ€” Enforcing Code Style

// .editorconfig โ€” place in solution root; applies to all files
// Controls: indentation, line endings, trailing whitespace, C# naming conventions

[*]
indent_style = space
indent_size  = 4
end_of_line  = crlf
charset      = utf-8-bom
trim_trailing_whitespace = true
insert_final_newline     = true

[*.cs]
csharp_style_namespace_declarations          = file_scoped:warning
csharp_prefer_braces                         = true:warning
dotnet_naming_rule.private_fields.style      = camel_case_underscore
dotnet_naming_rule.private_fields.symbols    = private_fields
dotnet_naming_rule.private_fields.severity   = warning

// โ”€โ”€ Format the entire codebase โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
dotnet format                              // fixes style violations in all files
dotnet format --verify-no-changes          // check only โ€” fails if violations found
// Run dotnet format --verify-no-changes in CI to enforce style gates

Common Mistakes

Mistake 1 โ€” Not using Directory.Build.props (property drift between projects)

โŒ Wrong โ€” each project has its own TargetFramework and Nullable settings; they drift and diverge over time.

โœ… Correct โ€” extract all shared properties into Directory.Build.props at the solution root; override in individual csproj only when needed.

Mistake 2 โ€” Skipping dotnet format in CI

โŒ Wrong โ€” code style inconsistency accumulates; developers argue about style in code reviews instead of logic.

โœ… Correct โ€” run dotnet format --verify-no-changes as a required CI step; fail the build if style violations exist.

🧠 Test Yourself

You have 6 projects in a solution. You want all of them to target net8.0 and have Nullable enabled. What is the most maintainable way to configure this?