This episode automates the .NET development cycle: the dotnet CLI, MSBuild, and SDK-style projects, continuous integration with GitHub Actions, source generators and Roslyn analyzers, and code formatting, linting, and reproducible builds.

Large projects cannot rely on human hands alone. Episode 18 covers tooling and build automation: how to make sure every commit is built, tested, and formatted the same way — on anyone's machine, at any time.
You will look inside the dotnet CLI and MSBuild, build a continuous integration pipeline with GitHub Actions, get to know source generators and Roslyn analyzers, and apply formatting and reproducible builds for a healthier team.
The dotnet commands are the front layer of MSBuild — the .NET build engine. Every SDK-style project is processed by MSBuild, and the CLI provides concise commands for common operations:
dotnet restore
dotnet build --no-restore
dotnet test --no-build
dotnet publish -c Release --no-restoreThe command chain above builds an efficient local pipeline: restore fetches packages, build compiles, test runs the tests, and publish produces artifacts. The --no-restore and --no-build flags avoid repeated work.
To make all developers use the same SDK, pin the version with global.json:
{
"sdk": {
"version": "9.0.100",
"rollForward": "latestPatch"
}
}global.json ensures developer machines and CI use exactly the same SDK version. rollForward: latestPatch allows the newest patch without changing the minor version — a first step toward reproducible builds.
Every push to main should trigger a build and test pipeline. The .github/workflows/ci.yml file:
name: CI
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'
- run: dotnet restore
- run: dotnet build --no-restore
- run: dotnet test --no-buildThis workflow checks out the code, installs the .NET 9 SDK, then runs restore, build, and test. If any step fails, CI turns red and the release is blocked — quality becomes an automatic gate, not a promise.
After the tests pass, save the publish output as an artifact:
- run: dotnet publish -c Release -o publish --no-build
- uses: actions/upload-artifact@v4
with:
name: app-publish
path: publishactions/upload-artifact saves the publish folder so it can be downloaded or used by the next deployment pipeline. In episode 19, this is the artifact that will be wrapped in Docker.
A source generator produces C# code at compile time — removing manual boilerplate. The most common example is the JSON source generator, which uses reflection-free serialization:
[JsonSerializable(typeof(Produk))]
public partial class AppJsonContext : JsonSerializerContext
{
}
string json = JsonSerializer.Serialize(new Produk(1, "Laptop"), AppJsonContext.Default.Produk);AppJsonContext is generated at build time into serialization metadata without runtime reflection. The result is faster serialization and a smaller footprint — source generators are one of the modern strengths of .NET.
Roslyn analyzers run code rules at compile time — catching pattern bugs before runtime:
dotnet add package Microsoft.CodeAnalysis.NetAnalyzersThis package brings hundreds of rules that run at build time. Rules can be promoted to errors for strict quality. Source generators and analyzers work together: one produces code, the other supervises its quality.
Consistent formatting removes style debates. dotnet format formats the entire solution according to .editorconfig:
dotnet format
dotnet format --verify-no-changesdotnet format --verify-no-changes checks whether the code is already formatted — without changing files. Run it in CI: if anything is untidy, the build fails. This forces the whole team to follow the same rules.
For deterministic output, enable reproducible builds:
dotnet publish -c Release -p:ContinuousIntegrationBuild=trueContinuousIntegrationBuild=true makes paths and build timestamps deterministic — the same commit produces the same artifacts. This matters for security audits and source verification, because binaries can be reproduced by anyone.
Info
Local builds and CI must run from the same commands. Document the CI pipeline as the single source of truth — not manual instructions that can differ between machines.
Key takeaways:
In the next episode 19 we will discuss deployment and cloud native — Dockerizing .NET applications, deployment to Kubernetes, Azure, AWS, and GCP, managing configuration, secrets and runtime environments, and blue-green deployment, canary releases, and rollbacks.