---
title: "Directory.Build.props - Centralize your builds"
description: "MSBuild has several extensibility hooks to customize your build and today we discover one which let you centralized repeating aspects of your C# projects. **Directory.Build.props**"
updated: 2022-02-13
tags: ["MSBuild", "C#"]
canonical: "https://steven-giesel.com/blogPost/f3f46814-06c9-41b7-84fa-09ebb3305ed0/directorybuildprops-centralize-your-builds"
---

# Directory.Build.props - Centralize your builds

The **Directory.Build.props** works almost like a "normal" csproj file. You can define default dependencies or even apply implicit usings. That is for example very convenient when you have a test project where you might always want to import `Moq` and `XUnit` namespace due to your setup.

## How does it work?
It is simple. MSBuild will traverse from your current csproj path upwards to file-hierarchy and selects **the first** <sub>More to that later</sub> **Directory.Build.props** it can find and includes it. Have us a look at the following file-structure:

```no-class
src/
+- Infrastructure/
¦  +- Infrastructure.csproj
+- Tools/
¦  +- Tools.csproj
+- Web/
¦  +- Web.csproj
+- Directoy.Build.props
```

Under our `src` there is directly the **Directory.Build.props** and then we have some folders which contain the "real" projects.
Those "real" projects automatically import our **Directory.Build.props**.

Let us have a look at an example:
```xml
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
	<ItemGroup>
      <PackageReference Include="SonarAnalyzer.CSharp" Version="8.35.0.42613">
        <PrivateAssets>all</PrivateAssets>
        <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      </PackageReference>
      <PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.406">
        <PrivateAssets>all</PrivateAssets>
        <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      </PackageReference>
    </ItemGroup>

    <ItemGroup>
        <AdditionalFiles Include="$(SolutionDir)\stylecop.json" Link="stylecop.json" />
    </ItemGroup>
    <PropertyGroup>
        <CodeAnalysisRuleSet>$(SolutionDir)\stylecop.analyzers.ruleset</CodeAnalysisRuleSet>
    </PropertyGroup>

    <PropertyGroup>
        <WarningLevel>5</WarningLevel>
        <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
    </PropertyGroup>

</Project>
```
<sub>This is taken directly from my blog github repository: [here](https://github.com/linkdotnet/Blog/blob/master/src/Directory.Build.props)</sub>

So in our case `Infrastructure.csproj`, `Web.csproj` and `Tools.csproj` will automatically include `SonarAnalyzer.CSharp` and `StyleCop.Analyzers` as nuget package. If I update the version in my **Directory.Build.props** all of them get automatically updated!

**Another example:**<br>
Let's say you have the following test setup:
```no-class
tests/
+- IntegrationTests/
¦  +- IntegrationTest.csproj
+- TestUtilities/
¦  +- TestUtilities.csproj
+- UnitTests/
¦  +- UnitTest.csproj
+- Directory.Build.props
```
As the nature of tests you will most likely use one test framework throughout all of your tests plus the same mocking framework. I personally love `XUnit` for various reasons and `Moq` as mocking library. Therefore I want to use them in all my test projects.
So my **Directory.Build.props** would look like this:
```html
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <ItemGroup>
    <PackageReference Include="FluentAssertions" Version="6.5.1" />
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0-preview-20220131-20" />
    <PackageReference Include="Moq" Version="4.16.1" />
    <PackageReference Include="xunit" Version="2.4.2-pre.12" />
  </ItemGroup>

  <ItemGroup Label="Implicit usings">
    <Using Include="FluentAssertions" />
    <Using Include="Moq" />
    <Using Include="Xunit" />
  </ItemGroup>

</Project>
```
<sub>Taken from [here](https://github.com/linkdotnet/Blog/blob/master/tests/Directory.Build.props)</sub>

Super convenient, isn't it?

Now let's say the Tools project does not need all this includes and stuff or in general: *How can I exclude a project?*.
That is quite easy as we are using the normal syntax we would use in a csproj: `Condition`.
Taking the example from above, let us exclude the `TestUtilities.csproj`:
```html
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <ItemGroup Condition="$(MSBuildProjectName) != 'TestUtilities'">
    <PackageReference Include="FluentAssertions" Version="6.5.1" />
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0-preview-20220131-20" />
    <PackageReference Include="Moq" Version="4.16.1" />
    <PackageReference Include="xunit" Version="2.4.2-pre.12" />
  </ItemGroup>

  <ItemGroup Label="Implicit usings" Condition="$(MSBuildProjectName) != 'TestUtilities'">
    <Using Include="FluentAssertions" />
    <Using Include="Moq" />
    <Using Include="Xunit" />
  </ItemGroup>

</Project>
```
Also very simple. Just add the name of your project without the "csproj" file extension.

## Multiple Directory.Build.props
What happens if we have multiple **Directory.Build.props**?

```no-class
tests/
+- IntegrationTests/
¦  +- IntegrationTest.csproj
+- TestUtilities/
¦  +- TestUtilities.csproj
+- UnitTests/
¦  +- UnitTest.csproj
+- Directory.Build.props
Directory.Build.props
```

Now we have another **Directory.Build.props** one level above the "tests" folder. Well this one **will not** automatically get included. You have to tell MSBuild it should continue scanning. You can do this by adding this to the inner **Directory.Build.props** (the one under "tests").
```html
<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />
````

## Conclusion
**Directory.Build.props** gives you a handy tool the centralize common dependencies and configurations.

Further read [here on the Microsoft documentation](https://docs.microsoft.com/en-us/visualstudio/msbuild/customize-your-build?view=vs-2022)
