Create our first .NET Hello World
Now that we have the .NET SDK installed, we can use it to create our first application.
Create a console application
.NET provides project templates that give us a starting point for different types of applications.
We can see the available templates with:
dotnet new list
For our first application, we will use the Console App template:
dotnet new console -n HelloDotnet
This command has three important parts:
dotnet new console -n HelloDotnet
│ │ │ │
│ │ │ └── Project name
│ │ └───────────── Template
│ └──────────────────── Create from a template
└─────────────────────────── .NET CLI
Then we can enter the newly created directory:
cd HelloDotnet
What did .NET create?
Our project initially has a very simple structure:
HelloDotnet/
├── HelloDotnet.csproj
└── Program.cs
These two files have different responsibilities:
flowchart LR
Project["HelloDotnet"]
Code["Program.cs<br/>Our C# code"]
Config["HelloDotnet.csproj<br/>How the project is built"]
Project --> Code
Project --> Config
Program.cs
Program.cs contains our C# source code.
A new console application contains something similar to:
Console.WriteLine("Hello, World!");
For now, we only need to understand that this is the code our application will execute.
We will explore C# syntax in more detail in the next section.
.csproj
The .csproj file is the C# project file.
Open it and you will see something similar to:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
We don’t need to understand every property yet.
For now, the important idea is:
A project describes something .NET can build.
The .csproj file tells the .NET SDK about our project, including information such as its target framework, configuration, and dependencies.
For example:
<TargetFramework>net10.0</TargetFramework>
tells .NET that this project targets .NET 10.
As our application grows, the project file can also contain information about external packages and other projects it depends on.
We will return to the .csproj file later.
Build the application
We have source code and a project describing how it should be built.
Now we can ask the SDK to build it:
dotnet build
Conceptually:
flowchart LR
Source["C# source code<br/>Program.cs"]
Project["Project<br/>.csproj"]
SDK[".NET SDK"]
Output["Build output"]
Source --> SDK
Project --> SDK
SDK --> Output
During the build, .NET compiles our source code and produces the files necessary to run the application.
After building the project, our directory will contain two additional directories:
HelloDotnet/
├── bin/
├── obj/
├── HelloDotnet.csproj
└── Program.cs
bin/
bin contains the final build output.
For example:
bin/
└── Debug/
└── net10.0/
├── HelloDotnet
├── HelloDotnet.dll
├── HelloDotnet.deps.json
└── HelloDotnet.runtimeconfig.json
These are files produced from our source code that are used to execute the application.
A useful mental model is:
**bin/**= build output
obj/
obj contains intermediate files that the build process uses while creating the final output.
These files help MSBuild and the .NET SDK perform the build efficiently.
For now, we can think of it as:
**obj/**= intermediate build files
Normally, we don’t manually edit files inside either bin/ or obj/.
flowchart TD
Source["📄 <b>Source files</b><br/><span style='font-size:14px'>Program.cs</span>"]
Build["⌨️ <b>dotnet build</b><br/><span style='font-size:14px'>.NET SDK<br/>(compiles the project)</span>"]
Obj["📁 <b>obj/</b><br/><span style='font-size:14px'>Intermediate files<br/>(used during build)</span>"]
Bin["📦 <b>bin/</b><br/><span style='font-size:14px'>Build output<br/>(compiled application)</span>"]
Source --> Build
Build --> Obj
Build --> Bin
style Source fill:#DDF4DD,stroke:#3F9855,stroke-width:2px
style Build fill:#D8EDFF,stroke:#1683D8,stroke-width:2px
style Obj fill:#FFF0B8,stroke:#E89B00,stroke-width:2px
style Bin fill:#E9DFFF,stroke:#6040C8,stroke-width:2px
Run the application
Once our application can be built, we can run it:
dotnet run
And we should see:
Hello, World!
dotnet run is convenient during development because it handles the build when necessary and then runs the application.
Conceptually:
flowchart LR
Code["Program.cs"] --> Build["Build"]
Project[".csproj"] --> Build
Build --> App["Application"]
App --> Output["Hello, World!"]
The complete picture
We have now gone through the basic lifecycle of a .NET project:
flowchart LR
Create["Create<br/><code>dotnet new</code>"]
Code["Write<br/>C#"]
Build["Build<br/><code>dotnet build</code>"]
Run["Run<br/><code>dotnet run</code>"]
Create --> Code --> Build --> Run
And our project has four important elements:
| Element | Purpose |
|---|---|
Program.cs | Contains our C# source code |
.csproj | Describes the project and how .NET should build it |
obj/ | Contains intermediate build files |
bin/ | Contains the final build output |
The most important distinction at this point is:
- Program.cs - What should my application do?
- .csproj - What am I building and how should .NET build it?
Now that we understand where our code lives and how .NET builds it, we can start learning the C# language itself.