When working with .NET projects, you may notice that your project uses NuGet packages that you never explicitly installed. This can be confusing when you're troubleshooting package version conflicts, warnings, or errors in Visual Studio.

The reason is that NuGet packages can be either direct dependencies or transitive dependencies.

Understanding the difference between them makes it much easier to understand your project's dependency tree and troubleshoot NuGet package conflicts.


๐Ÿ“ฆ What Is a Direct NuGet Dependency?

A direct dependency is a NuGet package that your project explicitly references.

For example, suppose your .csproj file contains:

<ItemGroup>
    <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>

Your application directly references Newtonsoft.Json.

Therefore, Newtonsoft.Json is a direct dependency of your project.


๐Ÿ”— What Is a Transitive NuGet Dependency?

A transitive dependency is a package that your project receives indirectly because another package depends on it.

For example:

Your Application
       โ”‚
       โ””โ”€โ”€ Package A
              โ”‚
              โ””โ”€โ”€ Package B

If your project directly references Package A, but Package A requires Package B, then:

You didn't explicitly add Package B to your project, but NuGet restores it because Package A requires it.


๐Ÿงฉ A Simple Real-World Example

Imagine your project contains:

<ItemGroup>
    <PackageReference Include="PackageA" Version="5.0.0" />
</ItemGroup>

Package A itself depends on Package B:

PackageA 5.0.0
    โ†“
PackageB 3.0.0

Your project's dependency tree therefore looks like:

YourProject
    โ”‚
    โ””โ”€โ”€ PackageA 5.0.0
            โ”‚
            โ””โ”€โ”€ PackageB 3.0.0

Your project directly references Package A, while Package B is brought into the project transitively.


๐Ÿ“‹ Direct vs Transitive Dependencies

Direct Dependency Transitive Dependency
Explicitly referenced by your project Introduced by another package
Usually appears in the project file May not appear as a direct PackageReference
You choose its package version directly Version is initially determined through dependency resolution
Easy to identify in the .csproj file May require dependency-tree inspection

๐Ÿ“„ Where Do Direct Dependencies Appear?

Direct package references normally appear inside your project's .csproj file.

For example:

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
    </PropertyGroup>

    <ItemGroup>
        <PackageReference Include="PackageA" Version="5.0.0" />
        <PackageReference Include="PackageC" Version="2.1.0" />
    </ItemGroup>

</Project>

In this example, both Package A and Package C are direct dependencies.


๐Ÿ” Where Do Transitive Dependencies Come From?

Transitive dependencies come from the packages your project already references.

For example:

YourProject
    โ”‚
    โ”œโ”€โ”€ PackageA
    โ”‚      โ”œโ”€โ”€ PackageB
    โ”‚      โ””โ”€โ”€ PackageC
    โ”‚
    โ””โ”€โ”€ PackageD
           โ””โ”€โ”€ PackageE

Here:


๐Ÿ’ป How to See Direct Dependencies

One easy way to see your project's packages is to use the .NET CLI.

Open a terminal in your project directory and run:

dotnet list package

This shows the packages directly referenced by the project.

You can also inspect the project's .csproj file to see its PackageReference entries.


๐Ÿ”Ž How to See Transitive Dependencies

To inspect transitive dependencies, run:

dotnet list package --include-transitive

This is particularly useful when a package mentioned in a NuGet warning or error doesn't appear directly in your project's .csproj file.

You may see output similar to:

Top-level Package
> PackageA 5.0.0
> PackageC 2.1.0

Transitive Package
> PackageB 3.0.0
> PackageD 4.2.0
> PackageE 1.5.0

The transitive section helps reveal packages that are being included indirectly.


๐ŸŒณ Understanding the Dependency Tree

Think of NuGet dependencies as a tree.

Your Application
โ”‚
โ”œโ”€โ”€ Package A
โ”‚   โ”‚
โ”‚   โ”œโ”€โ”€ Package B
โ”‚   โ”‚   โ””โ”€โ”€ Package X
โ”‚   โ”‚
โ”‚   โ””โ”€โ”€ Package C
โ”‚
โ””โ”€โ”€ Package D
    โ”‚
    โ””โ”€โ”€ Package X

In this example:

Notice that Package X is required by both Package B and Package D. This type of situation can eventually result in a package version conflict if the packages require incompatible versions.


โš ๏ธ Why Transitive Dependencies Can Cause Problems

Transitive dependencies are convenient because you don't have to manually install every package required by another package.

However, they can also make dependency conflicts harder to understand.

Consider:

YourProject
โ”‚
โ”œโ”€โ”€ PackageA
โ”‚      โ””โ”€โ”€ CommonLibrary 1.x
โ”‚
โ””โ”€โ”€ PackageB
       โ””โ”€โ”€ CommonLibrary 2.x

Your project only directly references Package A and Package B. However, both packages require different versions of CommonLibrary.

The actual conflict involves a package that you never explicitly added.

This is one reason NuGet errors can sometimes appear confusing.


๐Ÿ”ง Why Understanding This Helps With NU1107

NU1107 is a common example where understanding the dependency tree is useful.

You may have:

YourProject
โ”‚
โ”œโ”€โ”€ PackageA
โ”‚      โ””โ”€โ”€ DependencyX 1.0
โ”‚
โ””โ”€โ”€ PackageB
       โ””โ”€โ”€ DependencyX 2.0

Your project doesn't necessarily reference DependencyX directly. It is being introduced transitively.

Understanding the dependency chain helps you determine whether you should update Package A, update Package B, or explicitly reference a compatible version of Dependency X.

For a complete NU1107 troubleshooting guide, see:

๐Ÿ”ง How to Fix NU1107: Version Conflict Detected for NuGet Package


๐Ÿ”„ Can a Transitive Dependency Become Direct?

Yes.

Suppose Package B is currently brought into your project through Package A:

YourProject
    โ†“
PackageA
    โ†“
PackageB

You can explicitly add Package B to your project:

<PackageReference Include="PackageB" Version="3.0.0" />

Package B is now a direct dependency of your project.

This can be useful when you intentionally need to control the version of a dependency.

However, explicitly referencing a transitive dependency should be done carefully. The selected version should be compatible with the packages that depend on it.


๐Ÿง  Why NuGet Doesn't Require You to Install Everything Manually

One of the biggest advantages of NuGet is that you don't need to manually install every dependency required by your packages.

For example:

YourProject
    โ†“
WebFrameworkPackage
    โ†“
LoggingPackage
    โ†“
ConfigurationPackage

You only need to add the package you actually want to use. NuGet resolves the packages required by that package automatically.

These indirect packages become part of your project's dependency graph.


๐Ÿ› ๏ธ What Should You Do When a Transitive Dependency Conflicts?

Don't immediately force a version or remove the dependency.

First identify the complete dependency chain.

  1. Read the NuGet warning or error.
  2. Identify the conflicting dependency.
  3. Run dotnet list package --include-transitive.
  4. Find which packages depend on it.
  5. Compare the required versions.
  6. Check whether the parent packages have newer versions.
  7. Choose a compatible resolution.
  8. Restore and rebuild the project.

If you're not sure which package introduced the conflict, our previous article explains how to trace the dependency:

๐Ÿ” How to Check Which NuGet Package Is Causing a Dependency Conflict


๐Ÿ“Œ Direct and Transitive Dependencies in One Example

Let's put everything together.

YourProject
โ”‚
โ”œโ”€โ”€ PackageA 5.0.0       โ† Direct
โ”‚   โ”‚
โ”‚   โ”œโ”€โ”€ PackageB 3.0.0   โ† Transitive
โ”‚   โ”‚   โ””โ”€โ”€ PackageX 1.0 โ† Transitive
โ”‚   โ”‚
โ”‚   โ””โ”€โ”€ PackageC 2.0.0   โ† Transitive
โ”‚
โ””โ”€โ”€ PackageD 4.0.0       โ† Direct
    โ”‚
    โ””โ”€โ”€ PackageX 2.0     โ† Transitive

Here, your project directly references:

The remaining packages are transitive dependencies.

Package X is particularly important because two different dependency paths require different versions:

PackageA
    โ†“
PackageB
    โ†“
PackageX 1.0

PackageD
    โ†“
PackageX 2.0

This is exactly the kind of dependency tree that can lead to version conflicts.


โ“ Frequently Asked Questions

What is a direct NuGet dependency?

A direct NuGet dependency is a package explicitly referenced by your project, usually through a PackageReference in the .csproj file.

What is a transitive NuGet dependency?

A transitive dependency is a package that your project receives because another package depends on it.

How can I see transitive NuGet dependencies?

Run:

dotnet list package --include-transitive

Can I directly reference a transitive dependency?

Yes. You can add it as a PackageReference, but make sure the selected version is compatible with the packages that depend on it.

Why do I have packages that I never installed?

They are often transitive dependencies. Another package in your project requires them, so NuGet restores them automatically.


๐Ÿ“š Related NuGet Articles

๐Ÿ“ฆ How to Fix NuGet Package Version Conflicts in Visual Studio

๐Ÿ”ง How to Fix NU1107: Version Conflict Detected for NuGet Package

๐Ÿ” How to Check Which NuGet Package Is Causing a Dependency Conflict


๐ŸŽฏ Conclusion

The difference between direct and transitive NuGet dependencies is simple: direct dependencies are explicitly referenced by your project, while transitive dependencies are brought in by other packages.

When troubleshooting NuGet problems, don't look only at the packages in your .csproj file. A conflicting package may be several levels deeper in the dependency tree.

The command:

dotnet list package --include-transitive

is a useful starting point for understanding those hidden dependencies.

๐Ÿ“ฆ Still having a NuGet dependency conflict?

Start with the complete guide: How to Fix NuGet Package Version Conflicts in Visual Studio โ†’

๐Ÿค– AlgoLassi Assistant Have a question about this tutorial?

Ask AlgoLassi and get an answer plus the tutorials worth studying next.

Ask a question

๐Ÿ’ฌ Comments

Sign in with Google to publish immediately, or comment anonymously and wait for approval.

Comments will appear here when available.