Common Files and Directories in a C# Project and Solution

A C# solution is usually made up of one or more projects. The projects contain the code and configuration needed to build applications or libraries, while the solution groups those projects for development and tooling.

A typical repository might look like this:

Contoso.Inventory/
├── Contoso.Inventory.slnx
├── global.json
├── Directory.Build.props
├── Directory.Packages.props
├── src/
│   └── Contoso.Inventory.Api/
│       ├── Contoso.Inventory.Api.csproj
│       ├── Program.cs
│       └── Properties/
│           └── launchSettings.json
├── tests/
│   └── Contoso.Inventory.Tests/
│       └── Contoso.Inventory.Tests.csproj
├── bin/
└── obj/

Solution files: .sln and .slnx

An .sln file describes a Visual Studio solution. It lists the projects in the solution and stores solution-level configuration such as build configurations. It does not contain the application’s source code.

The newer .slnx format is an XML-based solution format designed to be simpler and easier for tools and developers to understand. The .NET SDK added support for .slnx in SDK version 9.0.200. With the .NET 10 SDK, dotnet new sln creates an .slnx file by default; older SDKs generally create an .sln file.

Most teams should commit the solution file they use. Do not commit both formats unless the repository has a specific reason to support both.

Project files: .csproj

Each C# project normally has a .csproj file. It defines how the project is built, including its target framework, package references, project references, and build settings:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Serilog" Version="4.0.0" />
    <ProjectReference Include="../Contoso.Inventory.Domain/Contoso.Inventory.Domain.csproj" />
  </ItemGroup>
</Project>

Modern SDK-style projects automatically include many .cs files, so a project file is often much smaller than older .NET Framework project files. The .csproj file should be committed because it is part of the project’s source and build definition.

Source files: .cs

Files with the .cs extension contain C# source code. A project can organize them into folders such as Controllers, Services, Models, or Infrastructure. The folder structure is for organization; namespaces and project references determine how code is related to other code.

Common source files include:

Program.cs          # Application entry point or host setup
OrderService.cs     # A class implementation
Order.cs            # A domain model or record
GlobalUsings.cs     # Optional shared using directives

bin directory

The bin directory contains build output, such as compiled assemblies, executables, symbol files, and runtime configuration files. It usually contains separate folders for configurations and target frameworks:

bin/
└── Debug/
    └── net8.0/
        ├── Contoso.Inventory.Api.dll
        ├── Contoso.Inventory.Api.exe
        └── Contoso.Inventory.Api.runtimeconfig.json

bin is generated by the build and should normally be excluded from source control. It can be safely regenerated by building the project again.

obj directory

The obj directory contains intermediate build files. These can include generated code, NuGet restore information, project assets, compiler inputs, and temporary files used by MSBuild.

Like bin, obj is generated and should normally be excluded from source control. If a build behaves strangely, deleting bin and obj and rebuilding is a common troubleshooting step.

global.json

global.json controls which installed .NET SDK the .NET CLI should use. It selects the SDK, not the runtime that the application targets:

{
  "sdk": {
    "version": "8.0.302",
    "rollForward": "latestFeature"
  }
}

This file is useful when a team or continuous-integration system needs a predictable SDK version. The .NET CLI searches for global.json in the current directory and parent directories, so it is commonly placed at the repository root. It should be committed when the project depends on a specific SDK version.

Directory.Build.props and Directory.Build.targets

Directory.Build.props and Directory.Build.targets allow shared MSBuild settings to be applied to multiple projects. They are useful for centralizing settings such as nullable reference types, analyzers, warning levels, or common output options:

<Project>
  <PropertyGroup>
    <Nullable>enable</Nullable>
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
  </PropertyGroup>
</Project>

Directory.Build.props is typically used for properties loaded early in the build. Directory.Build.targets is typically used for targets or settings that must be loaded later. These files are source-controlled project configuration, not generated output.

Directory.Packages.props

Directory.Packages.props is used for central package management. Instead of putting package versions in every .csproj file, a repository can define them in one place:

<Project>
  <PropertyGroup>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
  </PropertyGroup>

  <ItemGroup>
    <PackageVersion Include="Serilog" Version="4.0.0" />
  </ItemGroup>
</Project>

Projects can then reference the package without repeating its version. This reduces version drift across projects and makes upgrades easier to review.

packages.lock.json

When NuGet package lock files are enabled, packages.lock.json records the resolved dependency graph. It can make restores more reproducible, especially in continuous integration. Whether to commit it depends on the repository’s dependency-management policy.

NuGet.config

NuGet.config configures NuGet behavior, including package sources, package mappings, and cache-related settings. A repository may use it to point to an internal package feed in addition to or instead of nuget.org.

Because package sources can affect what code is restored, changes to this file should be reviewed carefully and committed only when they are intentional.

.editorconfig

.editorconfig defines formatting and code-style rules for editors and IDEs. It can specify indentation, naming rules, whitespace, and C# preferences. A repository-level .editorconfig helps developers produce consistent code regardless of their editor.

Properties/launchSettings.json

In many ASP.NET Core projects, Properties/launchSettings.json stores local development profiles. These profiles can define launch URLs, environment variables, and whether the application starts with a browser.

The file is intended for local development and should not be used to store production secrets. Some teams commit it because it describes shared local profiles; others keep machine-specific changes out of source control.

What should be committed?

Usually commit:

  • .sln or .slnx
  • .csproj files
  • .cs source files
  • global.json, when the SDK version is intentionally pinned
  • Shared build and package-management files
  • .editorconfig and intentional NuGet configuration

Usually ignore:

  • bin/
  • obj/
  • IDE-specific folders such as .vs/
  • User-specific files such as .user files

The exact policy can vary, but a useful rule is: commit files that describe the source or reproducible build, and ignore files produced by a local build or IDE.