Hot take: a clean laptop + 30 minutes + copy‑paste commands = a solid .NET box that ships code today. No drama, no yak‑shaving. In my projects I keep the setup lean, repeatable, and safe. Here’s the exact playbook: Visual Studio (or VS Code), Git that never argues, NuGet that just works, and a starter solution you can push right away.
What you’ll set up (quick map)
- .NET SDK (current LTS + optional preview)
- IDE: Visual Studio (Windows) or VS Code (any OS)
- Git with sane global config and SSH
- NuGet feeds, credentials, and central package versions
- Project skeleton: solution layout,
Directory.Build.props,.editorconfig - Quality gates: analyzers,
dotnet format, pre‑commit hook - HTTPS dev certs and hot reload
Works on Windows, macOS, and Linux. I’ll call out OS‑specific bits as we go.
Step 0 – Prereqs and fast install mindset
- You need admin rights on your machine.
- Keep PowerShell (Windows) or a shell (macOS/Linux) handy.
- Prefer a package manager. It makes updates painless.
Package managers
- Windows: winget or Chocolatey
- macOS: Homebrew
- Linux: your distro’s manager (apt, dnf, pacman) or Microsoft’s packages
Tip: save every command you run into a
bootstrapscript so you can replay it on a new machine.
Step 1 – .NET SDK
You want the latest LTS for production and optional Current for new APIs.
Windows (PowerShell)
# Install .NET SDK (example: 8.x LTS)
winget install --id Microsoft.DotNet.SDK.8 --source winget
# Optional: Current channel (adjust to your target)
# winget install --id Microsoft.DotNet.SDK.9 --source winget
# Verify
$Env:PATH += ";$Env:ProgramFiles\dotnet"
dotnet --infomacOS (Terminal)
# Homebrew
brew update
brew install --cask dotnet-sdk
# Verify
dotnet --infoLinux (Ubuntu example)
# Using Microsoft packages (example for SDK 8.x)
sudo apt-get update
sudo apt-get install -y dotnet-sdk-8.0 git
# Verify
dotnet --infoFast toggle: set
DOTNET_CLI_TELEMETRY_OPTOUT=1if your org requires it.
Step 2 – IDE: Visual Studio or VS Code
Visual Studio (Windows)
Install Community (free) or higher. Select workloads:
- .NET desktop development
- ASP.NET and web development
- Optional: Azure development, Data storage and processing
Once installed:
- Enable .NET analyzers (Project → Properties → Code Analysis).
- Turn on Hot Reload and Just My Code.
VS Code (cross‑platform)
Extensions I actually use:
- C# Dev Kit (Microsoft)
- C# (language support)
- NuGet Package Manager
- EditorConfig for VS Code
- GitLens (history and blame that doesn’t hurt)
Workspace settings snippet:
{
"dotnet.server.useOmnisharp": false,
"dotnet.defaultSolution": "YourApp.sln",
"editor.formatOnSave": true,
"csharp.format.enable": true
}Step 3 – Git you can trust
Install & first‑time setup
# Windows (winget)
winget install --id Git.Git --source winget
# macOS (brew)
brew install git
# Linux (Ubuntu)
sudo apt-get install -y gitGlobal config (works on any OS):
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global init.defaultBranch main
git config --global pull.rebase false
git config --global fetch.prune true
# Safer diffs
git config --global diff.mnemonicprefix true
# Line endings: recommend this on Windows only
git config --global core.autocrlf trueSSH keys (recommended)
# Create key
ssh-keygen -t ed25519 -C "you@example.com"
# Start agent and add key
ssh-agent -s
ssh-add ~/.ssh/id_ed25519
# Print public key to add in Git hosting
cat ~/.ssh/id_ed25519.pubUseful global .gitignore
Create ~/.gitignore_global and add:
# OS
.DS_Store
Thumbs.db
# IDE
.vs/
.vscode/
*.user
*.suo
# .NET
bin/
obj/
.nuget/
TestResults/Then:
git config --global core.excludesfile ~/.gitignore_globalStep 4 – NuGet that doesn’t leak secrets
Prefer CLI for feeds; your credentials land in the user profile, not in repo.
# Add nuget.org if missing
dotnet nuget add source https://api.nuget.org/v3/index.json \
--name nuget.org --store-password-in-clear-text false
# Add a private feed (sample)
dotnet nuget add source https://nuget.contoso.com/v3/index.json \
--name Contoso \
--username $NUGET_USER \
--password $NUGET_TOKEN \
--store-password-in-clear-text false
# List sources
dotnet nuget list sourceCentral Package Management (less version noise across projects):
Create Directory.Packages.props at the solution root:
<Project>
<ItemGroup>
<PackageVersion Include="Microsoft.Extensions.Logging" Version="8.0.0" />
<PackageVersion Include="FluentAssertions" Version="6.12.0" />
<PackageVersion Include="xunit" Version="2.6.4" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.5.6" />
</ItemGroup>
</Project>Enable it in Directory.Build.props:
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
</Project>Step 5 – Create a clean solution skeleton
I keep the layout boring and obvious:
YourApp/
src/
Api/
Core/
tests/
Api.Tests/
build/
.editorconfig
Directory.Build.props
Directory.Packages.props
YourApp.slnCreate it:
mkdir -p YourApp/src YourApp/tests YourApp/build
cd YourApp
dotnet new sln -n YourApp
# Web API
mkdir -p src/Api
cd src/Api
dotnet new webapi -n Api --no-https
cd ../..
dotnet sln add src/Api/Api.csproj
# Test project
dotnet new xunit -n Api.Tests -o tests/Api.Tests
dotnet add tests/Api.Tests/Api.Tests.csproj reference src/Api/Api.csprojDirectory.Build.props (recommended defaults)
<Project>
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<LangVersion>latest</LangVersion>
<Deterministic>true</Deterministic>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" PrivateAssets="all" />
</ItemGroup>
</Project>.editorconfig (keeps diffs small, code tidy)
root = true
[*.{cs,csproj}]
indent_style = space
indent_size = 4
end_of_line = lf
insert_final_newline = true
charset = utf-8
# C# style
csharp_new_line_before_open_brace = all
csharp_prefer_braces = true:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
csharp_style_var_elsewhere = true:suggestion
# Analyzer severity tweaks
dotnet_diagnostic.CA2007.severity = noneStep 6 – Minimal API, run, and HTTPS certs
Program.cs in src/Api:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/health", () => Results.Ok(new { ok = true, time = DateTimeOffset.UtcNow }));
app.Run();Run it with hot reload:
cd src/Api
dotnet watch runEnable local HTTPS (once):
# Windows/macOS
dotnet dev-certs https --trust
# Linux: create the cert, then trust it via your distro’s cert store
dotnet dev-certs httpslaunchSettings.json profile example:
{
"profiles": {
"Api": {
"commandName": "Project",
"dotnetRunMessages": true,
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}Step 7 – Tests and coverage
Add bread‑and‑butter tests:
using Xunit;
public class HealthTests
{
[Fact]
public void Demo() => Assert.True(1 + 1 == 2);
}Run:
dotnet test --collect:"XPlat Code Coverage"Optional coverage report (local):
dotnet tool install --global dotnet-reportgenerator-globaltool
reportgenerator -reports:**/coverage.cobertura.xml -targetdir:./coverageStep 8 – Format and a painless pre‑commit hook
Keep the repo clean by default:
# Format solution
dotnet format --verify-no-changes || dotnet formatLightweight Git hook:
mkdir -p .githooks
cat > .githooks/pre-commit << 'EOF'
#!/usr/bin/env bash
set -e
# Format C#
dotnet format --verify-no-changes || {
echo "✋ Code style issues found. Running dotnet format...";
dotnet format;
}
# Run a quick test slice (fast feedback)
dotnet test --no-build -c Release -m:1 || exit 1
EOF
chmod +x .githooks/pre-commit
git config core.hooksPath .githooksStep 9 – NuGet cache and restore speed tips
- Clear a messy cache:
dotnet nuget locals all --clear - Repro builds:
dotnet restore --locked-mode(with a lock file checked in) - Offline? Pre‑seed packages on CI and cache
~/.nuget/packages
Step 10 – One‑shot bootstrap scripts
Windows (PowerShell) – bootstrap.ps1
# Apps
winget install Microsoft.DotNet.SDK.8
winget install Git.Git
winget install Microsoft.VisualStudio.2022.Community
# Git
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global init.defaultBranch main
# HTTPS dev cert
& dotnet dev-certs https --trustmacOS (shell) – bootstrap.sh
#!/usr/bin/env bash
set -e
brew update
brew install git
brew install --cask dotnet-sdk
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global init.defaultBranch main
dotnet dev-certs https --trustStep 11 – Troubleshooting quick wins
- Dotnet not found: ensure the SDK path is on
PATH, then open a new terminal. - 403 from private feed: re‑auth your source with
dotnet nuget update source. - Debugger can’t hit breakpoints: disable “Just My Code” if symbols are missing.
- HTTPS trust issues: re‑run
dotnet dev-certs https --trustand restart the IDE. - SSL on Linux: install
ca-certificatesand trust the dev cert with your distro tool. - Weird build after pull:
dotnet clean, clear NuGet locals, thendotnet restore.
Bonus – A tiny API template you can reuse
dotnet new install . from a folder that contains these files, then:
template/.editorconfigtemplate/Directory.Build.propstemplate/Directory.Packages.propstemplate/src/Api/Program.cs
This gives you a repeatable baseline across teams.
FAQ: setup choices, versions, IDEs
No. VS Code + .NET SDK is enough for API and console work. Visual Studio shines for heavy UI, designers, and solid profilers.
Install LTS for production. Add Current side‑by‑side if you want to try new APIs. dotnet --list-sdks shows what’s installed.
Yes. Trust the dev cert once and keep it on. You’ll catch cookie and CORS issues early.
In your user profile. Don’t commit them. Use dotnet nuget add source so secrets never land in repo.
It stops version drift across projects and makes updates one‑line.
If your stack includes Linux‑only tools, WSL2 is great. For plain .NET, staying on Windows is simple and fast.
Keep bootstrap scripts and your .editorconfig in a repo. For VS Code, turn on Settings Sync.
Conclusion: from zero to commit in one sitting
You now have a clean .NET setup with predictable builds, a tidy Git config, NuGet feeds that don’t bite, and a starter solution you can run and test. Copy the snippets, tweak names, push a repo, and you’re rolling. Got a trick I should add? Drop it in the comments – I read them all.
