If you have worked with different versions of .NET and Visual Studio, you may have seen two different ways of managing NuGet packages: PackageReference and packages.config.
Both approaches can manage NuGet dependencies, but they work differently and are associated with different project types and .NET development styles.
In this guide, we'll compare PackageReference and packages.config, explain how they work, and help you understand which approach is appropriate for your project.
๐ฆ What Is PackageReference?
PackageReference is a NuGet package management format
where package dependencies are declared directly in the project file,
usually the .csproj file.
For example:
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
The package information is therefore part of the project definition.
PackageReference is commonly used by modern SDK-style .NET projects, including modern .NET applications.
๐ What Is packages.config?
packages.config is an older NuGet package management
format where package dependencies are stored in a separate XML file
named packages.config.
A typical file might look like this:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json"
version="13.0.3"
targetFramework="net48" />
<package id="Example.Package"
version="2.1.0"
targetFramework="net48" />
</packages>
Instead of putting package references directly inside the project file, the package list is maintained separately.
โ๏ธ PackageReference vs packages.config
| PackageReference | packages.config |
|---|---|
| Package information is stored in the project file | Package information is stored in packages.config |
| Common in modern SDK-style projects | Common in older .NET Framework projects |
| Supports transitive dependency management | Uses the older package management model |
| Usually produces a simpler project structure | Requires a separate packages.config file |
| Preferred for modern projects | Still found in many legacy projects |
๐ How PackageReference Works
With PackageReference, the package dependency is declared directly inside the project file.
For example:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json"
Version="13.0.3" />
</ItemGroup>
</Project>
The project file contains both the project configuration and its direct package references.
This makes the dependency declaration easy to see and manage alongside the rest of the project configuration.
๐ How packages.config Works
With packages.config, the project and package list are separate.
The project may contain a reference to a package, while the actual package information is stored in:
packages.config
For example:
<packages>
<package id="Newtonsoft.Json"
version="13.0.3"
targetFramework="net48" />
</packages>
This approach was widely used by older .NET Framework projects.
๐ณ Dependency Management Differences
One of the biggest differences is how dependencies are represented and resolved.
With PackageReference, NuGet can build a dependency graph containing direct and transitive dependencies.
Your Project
โ
โโโ PackageA โ Direct
โ โโโ PackageB โ Transitive
โ โโโ PackageC
โ
โโโ PackageD โ Direct
This makes understanding transitive dependencies particularly important when troubleshooting modern .NET projects.
You can inspect them with:
dotnet list package --include-transitive
For a detailed explanation of direct and transitive dependencies, see:
๐ฆ Direct vs Transitive NuGet Dependencies: What's the Difference?
๐ป Which Project Types Use PackageReference?
PackageReference is commonly associated with modern SDK-style projects.
Examples include:
- Modern .NET applications
- ASP.NET Core applications
- Console applications
- Class libraries
- Modern .NET MAUI projects
- Other SDK-style projects
A quick way to recognize an SDK-style project is to see a project file beginning with:
<Project Sdk="Microsoft.NET.Sdk">
๐๏ธ Which Projects Commonly Use packages.config?
packages.config is most commonly encountered in older .NET Framework projects.
For example, an older ASP.NET MVC or Windows Forms application may still contain:
packages.config
If you are maintaining an older application, there is no need to immediately change the package management format simply because PackageReference is newer.
First consider the project's framework, project format, dependencies, and migration requirements.
๐ Can You Move from packages.config to PackageReference?
In many supported project scenarios, migration from
packages.config to PackageReference is possible.
However, migration should be planned carefully, especially for older applications with many dependencies.
Before migrating, consider:
- Project type
- Target framework
- Package compatibility
- Build configuration
- Package dependencies
- Custom build scripts
- Existing project references
โ ๏ธ Why Migration Can Cause Problems
A legacy project may have packages that were designed around the older packages.config workflow.
During migration, you may encounter:
- Package compatibility issues
- Missing references
- Changed dependency resolution
- Build errors
- Configuration differences
- Package version conflicts
This is why migration should ideally be performed with source control enabled so that changes can be reviewed or reverted if necessary.
๐งฉ PackageReference and Transitive Dependencies
PackageReference makes transitive dependencies an important part of understanding your project's dependency graph.
Suppose your project directly references:
PackageA 5.0.0
Package A requires:
PackageB 3.0.0
Your project therefore receives Package B transitively.
YourProject
โ
โโโ PackageA 5.0.0
โ
โโโ PackageB 3.0.0
If another direct dependency requires a different version of Package B, NuGet has to resolve those version requirements.
This can result in dependency warnings or errors.
๐จ PackageReference and NuGet Conflicts
When working with PackageReference, a dependency conflict can sometimes involve a package that isn't directly listed in your project file.
For example:
YourProject
โ
โโโ PackageA
โ โโโ CommonLibrary 1.x
โ
โโโ PackageB
โโโ CommonLibrary 2.x
Neither Package A nor Package B may appear to be the obvious source of the problem when you first see the error.
Inspecting the dependency tree can reveal the complete chain.
If you're experiencing a package version conflict, start here:
๐ฆ How to Fix NuGet Package Version Conflicts in Visual Studio
๐ How to Identify Your Project's Package Management Format
The easiest way is to inspect the project files.
If you see:
<PackageReference Include="Some.Package"
Version="1.0.0" />
your project is using PackageReference for that package.
If you see a file named:
packages.config
the project is using the packages.config format.
๐ Which One Should You Use?
For a new modern .NET project, PackageReference is generally the preferred approach.
It integrates naturally with SDK-style projects and provides modern dependency management capabilities.
However, if you are maintaining an existing legacy project that uses packages.config, changing the package management format isn't automatically necessary.
The best choice depends on your project type and whether migration provides a meaningful benefit.
๐ ๏ธ Practical Recommendation
| Situation | Recommended Approach |
|---|---|
| New modern .NET project | PackageReference |
| Existing SDK-style project | PackageReference |
| Older .NET Framework project | Evaluate the existing setup before migrating |
| Legacy application that works correctly | Don't migrate without a specific reason |
โ Frequently Asked Questions
What is the difference between PackageReference and packages.config?
PackageReference stores package references directly in the project file,
while packages.config stores package information in a separate
packages.config file.
Is PackageReference newer than packages.config?
Yes. PackageReference is the modern NuGet package management approach commonly used by SDK-style projects, while packages.config is associated with the older project model.
Should I convert every packages.config project?
No. Migration should be considered based on the project type, package compatibility, target framework, and the benefits you expect from the migration.
Does PackageReference support transitive dependencies?
Yes. Understanding transitive dependencies is an important part of working with PackageReference-based projects.
Can packages.config cause NuGet dependency problems?
NuGet dependency problems can occur with either package management approach. The exact cause depends on the project's dependencies, package versions, framework, and package resolution requirements.
๐ 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
๐ฆ Direct vs Transitive NuGet Dependencies: What's the Difference?
๐ How to Update NuGet Packages Safely Without Breaking Your Project
๐ฏ Conclusion
PackageReference and packages.config are two different approaches to managing NuGet dependencies.
PackageReference integrates package references directly into the project file and is commonly used by modern SDK-style projects.
packages.config uses a separate XML file and is commonly encountered in older .NET Framework projects.
If you're creating a new modern .NET application, PackageReference is generally the natural choice. If you're maintaining an existing legacy project, however, there may be no reason to migrate unless you have a specific need.
Continue with the main troubleshooting guide: How to Fix NuGet Package Version Conflicts in Visual Studio โ
Ask AlgoLassi and get an answer plus the tutorials worth studying next.
๐ฌ Comments
Sign in with Google to publish immediately, or comment anonymously and wait for approval.
Comments will appear here when available.