[Setup] C# Development Environment
To write and run C# programs, you need the .NET SDK (Software Development Kit). This page walks you through installing the SDK and running your first program.
Installing the .NET SDK
| OS | Installation Method |
|---|---|
| Windows | Download and run the installer from dotnet.microsoft.com. |
| macOS | Run brew install dotnet-sdk with Homebrew. Homebrew is a package manager for macOS. If it is not installed, follow the instructions on the official site (https://brew.sh/) to install it. Alternatively, download the installer from the official site. |
About downloading the installer
When you download the installer from the official site, your OS and architecture should be detected automatically when you open the page. Click the "Download .NET SDK XXX" button.

Windows installation steps
Double-click the downloaded installer to run it.

Click "Install" to start the installation.
When the following screen appears, click "Yes".

When the following screen appears, the installation is complete. Click "Close" to exit the installer.

Verifying the installation on Windows
Open PowerShell or Command Prompt and run the following.
dotnet --version 9.0.313
If a version number is displayed, the installation was successful.
Installing on macOS
Open a terminal and run the following command. If Homebrew is not installed, follow the instructions at https://brew.sh/ to install it first.
brew install dotnet-sdk ==> Installing Cask dotnet-sdk ==> Running installer for dotnet-sdk with `sudo` (which may request your password)... Password: installer: Package name is Microsoft .NET SDK 10.0.201 (arm64) installer: Upgrading at base path / installer: The upgrade was successful. ==> Linking Binary 'dotnet' to '/opt/homebrew/bin/dotnet' 🍺 dotnet-sdk was successfully installed!
You will be prompted for your administrator password during installation ("Password:" will appear). Enter your Mac login password and press Enter. Nothing will be displayed while typing, but this is normal behavior.
Verifying the installation on macOS
After installation, open a terminal and run the following.
dotnet --version 10.0.201
If a version number is displayed, the installation was successful.
Disabling Telemetry (Usage Data Collection)
The .NET CLI (Command Line Interface — a text-based interface for entering commands) displays a message on first run indicating that telemetry (usage data collection) is enabled.
Telemetry --------- The .NET tools collect usage data in order to help us improve your experience. The data is collected by Microsoft and shared with the community. You can opt-out of telemetry by setting the DOTNET_CLI_TELEMETRY_OPTOUT environment variable to '1' or 'true' using your favorite shell. Read more about .NET CLI Tools telemetry: https://aka.ms/dotnet-cli-telemetry
If you want to disable data collection, set the following environment variable.
For zsh:
echo 'export DOTNET_CLI_TELEMETRY_OPTOUT=1' >> ~/.zshrc source ~/.zshrc
For bash:
echo 'export DOTNET_CLI_TELEMETRY_OPTOUT=1' >> ~/.bashrc source ~/.bashrc
For Windows, go to "Advanced System Settings" → "Environment Variables" and set DOTNET_CLI_TELEMETRY_OPTOUT to 1.
Creating and Running a Project
C# programs are managed as projects. You can create, build, and run a project using the dotnet command.
1. Create a project
dotnet new console -n HelloApp The template "Console App" was created successfully.
dotnet new console creates a console application (CUI application) template. Here, "console" means a program that runs in the terminal without a GUI. -n HelloApp sets the project name. Running this command creates a HelloApp directory in the current directory, with the project files inside it. If you omit -n, no new directory is created and the files are generated directly in the current directory (the directory name becomes the project name). For example, running this on your desktop would result in a project named "Desktop", so it is recommended to always specify a project name with -n.
Move into the created HelloApp directory.
cd HelloApp
The following files are created.
| File / Directory | Description |
|---|---|
| Program.cs | The main source file. Write your code here. |
| HelloApp.csproj | The project configuration file. See Configuration Files for details. |
| bin/ | The directory where build output (DLL files, etc.) is stored. Auto-generated when you run dotnet build or dotnet run. |
| obj/ | A build cache directory used internally by .NET. It is auto-generated and does not need to be edited manually. |
2. Review and edit the source code
Open the auto-generated Program.cs and you will see the following code.
Console.WriteLine("Hello, World!");
Try editing it to something like this.
Console.WriteLine("Gojo Satoru");
Console.WriteLine("Ryomen Sukuna");
3. Run
dotnet run Gojo Satoru Ryomen Sukuna
If Gojo Satoru and Ryomen Sukuna are displayed in the console, you're all set.
Choosing an Editor or IDE (Integrated Development Environment — a tool combining code editing, execution, and debugging)
| Tool | Description |
|---|---|
| Visual Studio | Microsoft's integrated development environment. The Community edition is free on Windows. Offers rich debugging and code completion features. |
| Visual Studio Code (commonly known as VSCode) | A lightweight editor. Installing the C# Dev Kit extension adds code completion and debugging support. |
| Rider | A C#/.NET IDE by JetBrains. Offers advanced code analysis, refactoring, and debugging. Available on Windows, macOS, and Linux. Paid. |
It is a good idea to get comfortable with the dotnet run workflow on the command line first, then choose your preferred editor.
Commonly Used dotnet Commands
| Command | Description |
|---|---|
| dotnet new console | Creates a console application (a program that runs in the terminal) project. |
| dotnet new web | Creates a web application project. |
| dotnet new classlib | Creates a class library (a DLL referenced by other projects) project. |
| dotnet run | Builds and runs the project. This is the usual command for development. |
| dotnet build | Builds the project (without running it). The output is generated as a DLL file under bin/Debug/, which you can run with dotnet bin/Debug/net10.0/ProjectName.dll. |
| dotnet build -c Release | Generates an optimized Release build (details below). Run it with dotnet bin/Release/net10.0/ProjectName.dll. |
| dotnet publish -c Release | Generates production-ready files (details below). |
| dotnet test | Runs a test project. |
| dotnet add reference | Adds a reference to another project. Used when referencing a class library. |
The dotnet new template (console / web / classlib) determines the initial files and project settings (.csproj) that are generated. Commands like dotnet build and dotnet run work the same across all templates.
| Command | Purpose | SDK | OutputType | Entry point | dotnet run |
|---|---|---|---|---|---|
| dotnet new console | CUI app | Microsoft.NET.Sdk | Exe | Main method | Runs in terminal |
| dotnet new web | Web app | Microsoft.NET.Sdk.Web | Exe | Main method | Starts a local web server (http://localhost:5000, etc.) |
| dotnet new classlib | Library | Microsoft.NET.Sdk | Library | None | Cannot run (reference only) |
| Term | Description |
|---|---|
| SDK | A setting that defines the project type, written at the top of the .csproj file. Microsoft.NET.Sdk.Web includes additional libraries and tools for web development. |
| OutputType | A .csproj setting that specifies the output format. Exe generates an executable, while Library generates a DLL to be referenced by other projects. Note that Exe is just the name of the setting value — it does not mean a Windows .exe file is generated. The actual build output is a DLL file (.dll) on all operating systems, which you run with dotnet ProjectName.dll. |
| Entry point | The starting point of program execution. In C#, the Main method serves as the entry point. A classlib (library) has no entry point since it is not executed on its own. |
When you run dotnet build, the output is placed under the bin/ directory within the project. This is not the system /bin directory — it is HelloApp/bin/, located directly inside the project directory. Debug and Release builds are stored in separate directories. The net10.0 part varies depending on your installed .NET SDK version (e.g., net8.0 for .NET 8).
Debug Build vs. Release Build
| Debug Build (default) | Release Build | |
|---|---|---|
| Purpose | Development and debugging | Production and distribution |
| Command | dotnet build | dotnet build -c Release |
| Performance | Slower (no optimization) | Faster (optimized) |
| Debug info | Included (shows error line numbers, etc.) | Removed |
| Output | bin/Debug/ | bin/Release/ |
The typical workflow is to use Debug builds during development, then generate a Release build when the application is ready for production. In day-to-day development, dotnet run handles both building and running in one step, so you don't need to worry about the contents of bin/.
Creating and Running a Web App (dotnet new web)
Using dotnet new web, you can create a web application project that starts a local web server for testing in your browser.
1. Create a project
dotnet new web -n HelloWeb
Running this command creates a HelloWeb directory in the current directory with the following files.
| File / Directory | Description |
|---|---|
| Program.cs | The main source file. Write routing and application logic here. |
| HelloWeb.csproj | The project configuration file. Specifies the SDK type and target framework. |
| appsettings.json | The application configuration file. Contains common settings such as log levels. |
| appsettings.Development.json | Configuration file for the development environment only. Does not affect production. Can override settings in appsettings.json. |
| obj/ | A build cache directory used internally by .NET. It is auto-generated and does not need to be edited manually. |
| Properties/launchSettings.json | Launch settings for development. Contains the local server port number, environment variables, etc. |
Move into the created HelloWeb directory.
cd HelloWeb
2. Review and edit the source code
Open the auto-generated Program.cs. It contains the following code.
Program.cs
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
app.MapGet("/", ...) defines what happens when a browser accesses / (the top page). Let's change the displayed text.
Program.cs
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Don't worry, I'm the strongest.");
app.Run();
3. Run the application
dotnet run
A message like the following will appear.
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5249
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
Open the displayed URL (in this example, http://localhost:5249) in your browser. The port number may vary depending on your environment.
If "Don't worry, I'm the strongest." is displayed in the browser, you're all set.
To stop the server, press Ctrl + C in the terminal.
Creating a Class Library (dotnet new classlib)
dotnet new classlib creates a template for a library (DLL) that is referenced and used by other projects. A library cannot be executed on its own.
1. Create a project
dotnet new classlib -n MyLibrary
Running this command creates a MyLibrary directory in the current directory with the following files.
| File / Directory | Description |
|---|---|
| Class1.cs | The default class file. You can rename it freely. |
| MyLibrary.csproj | The project configuration file. OutputType is set to Library. |
| obj/ | A build cache directory used internally by .NET. It is auto-generated and does not need to be edited manually. |
2. Edit the source code
Open the auto-generated Class1.cs and write the classes and methods to be exposed by the library.
Class1.cs
namespace MyLibrary;
public class Greeting
{
public static string GetMessage()
{
return "Don't worry, I'm the strongest.";
}
}
3. Build
Since a library cannot be executed on its own, use dotnet build instead of dotnet run.
cd MyLibrary dotnet build
A successful build generates bin/Debug/net10.0/MyLibrary.dll.
4. Reference from another project
To use the library from a console app or other project, add a reference. Move to the referencing project directory (HelloApp) and specify the path to the library's .csproj file.
cd ../HelloApp dotnet add reference ../MyLibrary/MyLibrary.csproj
Adding a reference automatically adds the following entry to HelloApp's .csproj.
<ItemGroup> <ProjectReference Include="..\MyLibrary\MyLibrary.csproj" /> </ItemGroup>
Writing this entry directly in the .csproj file has the same effect.
Call the library class from Program.cs.
Program.cs
using MyLibrary; Console.WriteLine(Greeting.GetMessage());
dotnet run Don't worry, I'm the strongest.
If the library method is called and "Don't worry, I'm the strongest." is displayed, you're all set.
Publishing for Production (dotnet publish)
To deploy a completed project to a production environment, use the dotnet publish command to generate release-ready files.
Publishing a Console App
Run the following in the project directory.
dotnet publish -c Release
Deploy-ready files are generated in the HelloApp/bin/Release/net10.0/publish/ directory.
Copy the entire contents of the publish/ directory to the target machine and run with the following command. The DLL alone will not work. Since multiple files are required together, it is common to distribute them as a zip archive.
If you have added a class library reference with dotnet add reference, the dotnet publish output shows the library's build path in a separate directory.
dotnet publish -c Release MyLibrary net10.0 succeeded (0.2s) → /Users/username/Desktop/MyLibrary/bin/Release/net10.0/MyLibrary.dll HelloApp net10.0 succeeded (0.1s) → bin/Release/net10.0/publish/
Looking at this output, it appears that MyLibrary.dll is written to a separate directory from HelloApp, but the built library DLL is automatically copied into the publish directory as well. You do not need to copy it manually. For example, if HelloApp references MyLibrary, the publish directory will contain both DLLs.
dotnet HelloApp.dll
If you want the user to run the application with the $ dotnet XXX format, the .NET runtime must be installed on the target machine (the user's PC). The runtime is the software required to execute a program. Development requires the SDK (runtime + development tools), but the runtime alone is sufficient for running applications.
If it is difficult to have the runtime installed on the target machine, the --self-contained option bundles the runtime with the application for distribution.
dotnet publish -c Release --self-contained -r osx-arm64
-r specifies the target platform (OS + CPU (Central Processing Unit — the processor that executes computations) architecture). Common values are listed below.
| Value | Target |
|---|---|
| osx-arm64 | macOS (Apple Silicon) |
| osx-x64 | macOS (Intel) |
| win-x64 | Windows (64-bit) |
| linux-x64 | Linux (64-bit) |
When published with --self-contained, the output goes to a path like bin/Release/net10.0/osx-arm64/publish/, where the platform name specified by -r is included in the path. This directory contains a native executable (HelloApp or HelloApp.exe on Windows) that can be run directly without the dotnet command. However, a large number of runtime DLLs and libraries (around 200 files) are also written to the publish directory. It does not generate a single executable file on its own.
cd bin/Release/net10.0/osx-arm64/publish ./HelloApp Don't worry, I'm the strongest.
To truly bundle everything into a single executable file, add -p:PublishSingleFile=true.
dotnet publish -c Release --self-contained -r osx-arm64 -p:PublishSingleFile=true
This packages the runtime and all files into one executable.
The only file required to run the application is the executable (HelloApp or HelloApp.exe). The .pdb files are for debugging and are not needed for distribution. On Windows, you can run it by simply double-clicking.
cd bin/Release/net10.0/osx-arm64/publish ./HelloApp Don't worry, I'm the strongest.
Note that with self-contained publishing, the entire runtime is included in the executable, so even a simple program will be tens of megabytes in size. For comparison, the same program written in C would produce a binary of only a few tens of kilobytes. This is because the C# executable bundles the entire .NET runtime (garbage collector, type system, standard libraries, etc.).
Publishing a Web App
When deploying a web app to a server, the .NET runtime (or SDK) is assumed to be installed on the server. Since the runtime is always present on a server running .NET, --self-contained is not needed. Like console apps, use dotnet publish to generate the release files.
There are two main deployment methods.
Method 1: Publish locally and transfer to the server
dotnet publish -c Release scp -r bin/Release/net10.0/publish/ user@server:/var/www/app/
Method 2: git pull on the server and publish there
git pull dotnet publish -c Release
Move to the directory containing the deploy-ready files and start with the following command.
dotnet HelloWeb.dll
When hosting a .NET app on a server, the typical setup is to place a web server such as Nginx or Apache as a reverse proxy in front of the dotnet HelloWeb.dll process.
For example, in PHP, Apache directly executes PHP files, but .NET works differently. A .NET web app has a built-in web server called Kestrel. When you run dotnet HelloWeb.dll, it starts as a persistent process. Nginx or Apache acts as a reverse proxy, forwarding external requests to Kestrel.
| PHP | .NET (C#) | |
|---|---|---|
| Execution | Apache directly executes PHP files | dotnet HelloWeb.dll runs as a persistent process |
| Web server | Apache / Nginx handles requests directly | Built-in Kestrel handles requests (Apache / Nginx acts as reverse proxy) |
| Process | PHP runs per request | App stays running and waits for requests |
This is the same architecture as Node.js Express or Python Django. When using cloud services (Azure App Service, AWS Elastic Beanstalk, etc.), you can deploy the dotnet publish output directly.
Since dotnet HelloWeb.dll runs as a persistent process, it must be stopped and restarted when deploying. In production, it is common to register the app as a systemd service and manage it with systemctl restart myapp.
systemd service configuration example (/etc/systemd/system/myapp.service)
[Unit] Description=My .NET Web App [Service] WorkingDirectory=/var/www/app/publish ExecStart=/usr/bin/dotnet /var/www/app/publish/HelloWeb.dll Restart=always RestartSec=10 Environment=ASPNETCORE_ENVIRONMENT=Production [Install] WantedBy=multi-user.target
This produces the following output:
sudo systemctl enable myapp sudo systemctl start myapp sudo systemctl status myapp
When deploying, restart the app.
sudo systemctl restart myapp
Creating and Running Tests (dotnet test)
dotnet test runs a test project. A test project is a collection of code that automatically verifies whether your program behaves correctly. You can write checks for things like whether values match expectations, whether types are correct, and whether conditions are met. In C#, tests are created as a separate project that references the main project.
1. Create a test project
There are several test project templates available. Here we use the standard xUnit framework.
dotnet new xunit -n HelloApp.Tests
This creates a HelloApp.Tests directory.
2. Add a reference to the target project
Reference the main project from the test project.
cd HelloApp.Tests dotnet add reference ../HelloApp/HelloApp.csproj
3. Prepare the class to test
Suppose HelloApp has the following class.
Calculator.cs
namespace HelloApp;
public class Calculator
{
public static int Add(int a, int b)
{
return a + b;
}
public static int Multiply(int a, int b)
{
return a * b;
}
}
4. Write the tests
Open UnitTest1.cs and write the test code.
UnitTest1.cs
using HelloApp;
namespace HelloApp.Tests;
public class CalculatorTest
{
[Fact]
public void Add_ReturnsCorrectSum()
{
int result = Calculator.Add(3, 5);
Assert.Equal(8, result);
}
[Fact]
public void Multiply_ReturnsCorrectProduct()
{
int result = Calculator.Multiply(4, 6);
Assert.Equal(24, result);
}
}
| Element | Description |
|---|---|
| [Fact] | An attribute indicating that the method is a test. It is automatically detected and run by dotnet test. |
| Assert.Equal(expected, actual) | Verifies that two values are equal. If they do not match, the test fails. |
5. Run the tests
dotnet test
When all tests pass, the following is displayed.
Passed! - Failed: 0, Passed: 2, Skipped: 0, Total: 2
When a test fails, the output shows which test failed and the expected vs. actual values.
Failed! - Failed: 1, Passed: 1, Skipped: 0, Total: 2 Failed CalculatorTest.Multiply_ReturnsCorrectProduct Expected: 24 Actual: 20
Besides xUnit, other test frameworks such as NUnit and MSTest are available. All can be run with dotnet test.
| Framework | Template Command | Characteristics |
|---|---|---|
| xUnit | dotnet new xunit | The standard .NET test framework. Simple and widely used. |
| NUnit | dotnet new nunit | Inspired by Java's JUnit. Offers a rich set of assertions. |
| MSTest | dotnet new mstest | Microsoft's official test framework. Strong integration with Visual Studio. |
Configuration Files
.NET projects use various configuration files depending on the purpose. Below is a summary of the major configuration files and their roles.
.csproj (Project Configuration)
An XML file that describes the basic project settings. It manages the SDK type, target framework, dependencies, and more.
HelloApp.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
</Project>
HelloWeb.csproj
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
</Project>
| Setting | Description |
|---|---|
| Sdk | Defines the project type. Web apps use Microsoft.NET.Sdk.Web. |
| OutputType | The output format. Exe for executables, Library for libraries. Can be omitted for web (defaults to Exe). |
| TargetFramework | The target .NET version. Should match the installed SDK. |
appsettings.json (App Configuration)
Describes application behavior settings in JSON. Auto-generated for web apps.
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
appsettings.Development.json is a configuration file for the development environment only. It overrides settings in appsettings.json and does not affect production.
launchSettings.json (Launch Settings)
Describes the local server launch settings for development. Placed inside the Properties/ directory.
Properties/launchSettings.json
{
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"applicationUrl": "http://localhost:5249",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
applicationUrl is the local server URL. The port number is randomly assigned when the project is created.
global.json (SDK Version Pinning)
Place this file in the project root to pin the .NET SDK version used by the project. Useful for ensuring consistent development environments across a team. It is not auto-generated and should be created manually only when needed.
global.json
{
"sdk": {
"version": "10.0.201"
}
}
nuget.config (Package Source Settings)
A file that configures where NuGet packages (external libraries) are fetched from. Normally, packages are fetched from the default nuget.org, so this file is not needed. It is used when accessing private package sources within an organization.
.sln (Solution File)
A file for managing multiple projects together. Not needed for small-scale development, but useful when managing a web app and a library together. Create one with the following commands.
dotnet new sln -n MySolution dotnet sln add HelloApp/HelloApp.csproj
If the Command Is Not Found
If your terminal displays dotnet: command not found, the PATH may not be configured correctly. Follow the steps below to check and fix the issue.
1. Find the command location
Check where the command is located.
which dotnet
If not found, check common installation locations.
ls /usr/local/share/dotnet/dotnet ls ~/.dotnet/dotnet
2. Check which shell you are using
echo $SHELL
If /bin/zsh is shown, edit ~/.zshrc; if /bin/bash is shown, edit ~/.bashrc.
3. Add to PATH
Once you know the command location, add the PATH to your shell configuration file.
For macOS (zsh):
echo 'export DOTNET_ROOT="/usr/local/share/dotnet"' >> ~/.zshrc echo 'export PATH="$DOTNET_ROOT:$PATH"' >> ~/.zshrc source ~/.zshrc
For Linux (bash):
echo 'export DOTNET_ROOT="/usr/local/share/dotnet"' >> ~/.bashrc echo 'export PATH="$DOTNET_ROOT:$PATH"' >> ~/.bashrc source ~/.bashrc
DOTNET_ROOT is an environment variable pointing to the .NET SDK installation directory. It is a good practice to set it alongside PATH, as some tools reference it.
For Windows, go to "Advanced System Settings" → "Environment Variables" → "Path" to add the entry. The installer usually sets this automatically, but if you installed manually, check that it is configured correctly.
Uninstalling the .NET SDK
If installed via Homebrew:
brew uninstall dotnet-sdk
If installed via the official installer (macOS):
sudo rm -rf /usr/local/share/dotnet sudo rm -rf /etc/paths.d/dotnet
For Windows, go to "Settings" → "Apps" → "Installed apps", find ".NET SDK", and uninstall it.
If you find any errors or copyright issues, please contact us.