Skip to content

Conversation

@ericstj
Copy link
Member

@ericstj ericstj commented Nov 18, 2025

This is first draft. I might be assuming too much familiarity with the problem space. Please provide feedback 🤝


Internal previews

📄 File 🔗 Preview link
docs/standard/library-guidance/dependencies-net.md docs/standard/library-guidance/dependencies-net

Added guidance for selecting .NET library dependency versions, including strategies, tradeoffs, and recommendations for library authors.
@ericstj ericstj requested a review from JamesNK as a code owner November 18, 2025 20:08
Copilot AI review requested due to automatic review settings November 18, 2025 20:08
@ericstj ericstj requested review from a team and IEvangelist as code owners November 18, 2025 20:08
@dotnetrepoman dotnetrepoman bot added this to the November 2025 milestone Nov 18, 2025
Copilot finished reviewing on behalf of ericstj November 18, 2025 20:11
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces comprehensive guidance for .NET library authors on selecting dependency versions when targeting multiple .NET framework versions. The document outlines three primary strategies (latest supported versions, TFM-specific versions, and branching), their tradeoffs, and provides concrete recommendations with code examples.

Key changes:

  • New guidance document explaining dependency version selection strategies for .NET libraries.
  • Decision matrix comparing engineering, servicing, and update friction costs across strategies.
  • Code examples demonstrating each approach using System.Text.Json references.

|---------------------------------------|------------------|------------------|------------------|
| Latest Supported Versions (Option 1) | Moderate | Low | Moderate |
| TFM-Specific Versions (Option 2) | Low | High | Low / Moderate |
| Branching | Low | Low | High |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
| Branching | Low | Low | High |
| Branching | Low | High | High |

Copy link
Member Author

@ericstj ericstj Nov 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, the engineering cost of the branching solution is low. Here I use "engineering" to mean steady-state engineering cost in main and I contrast that with "servicing cost". Let me know if you can think of a better term to use.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we should even give this option. What is an example of a library that would follow this? Where they basically only add new functionality to the latest TFM support? Are there any examples outside of the .NET Team?

Copy link
Member Author

@ericstj ericstj Nov 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the option for any product that leverages branches to control risk. I do think it's important to call this out, since it does relate to plenty of folks asking these questions, and shows customers how we solve this problem. It's also a fine compromise, since it can be done after the fact for an on-demand release (eg: a security bug, for instance).

I can run a scan of nuget to see which packages use branching like this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the top 100 non-microsoft packages, the following use branches to manage risk, determined by observing lower major versions published after higher major versions.

AWSSDK.Core
Castle.Core
Moq
AutoMapper
FluentValidation
Npgsql
FluentAssertions
NUnit
NLog
AWSSDK.S3
RabbitMQ.Client
FluentValidation.DependencyInjectionExtensions
Npgsql.EntityFrameworkCore.PostgreSQL
Elasticsearch.Net
AWSSDK.SecurityToken
FluentValidation.AspNetCore
NodaTime
jQuery
MessagePack
AWSSDK.SQS

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That query seems inconsistent with the definition of "Option 3: Branching"

but branch your library in sync with target frameworks. This is the same as Option 1, but each time a new framework is added, a new major version / branch is created to allow for updating the major version of dependencies and adding the new target framework.

The only packages in your list that I know does that are the 2 Npgsql ones.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, but folks can be familiar with branching a general strategy, just because they don't use it precisely the way described doesn't mean it's a foreign idea.

It's also important to understand that it's how all the .NET libraries deal with this problem, and what characteristics that creates.

Maybe I can add a note under branching that some .NET packages do this and drop support for past frameworks (to further reduce engineering cost in the current codebase) but how we DON'T recommend that folks do this in general for libraries since it requires consumers to multi-target their dependencies, while normal branching strategies just give folks the option to multi-target dependencies.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I can add a note under branching

That sounds good to me. Thanks

Show contrast to framework overlapping package and not.

Library authors face challenges when deciding which version of a .NET dependency to reference. Newer versions have more API and features, but may require a local redistribution increasing servicing responsibilities of the library and size of the application. The decision impacts:

- **Friction of updates** on older runtimes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This list of decision impacts is only focusing on the negatives. It doesn't touch on the benefits of utilizing newer features and APIs, bug fixes, performance improvements, etc., nor on what folks need to do to work around the lack of such things, like polyfills, which can be both hard to get right (if possible to get 100% right) and require substantial amounts of code.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do cover that below, I see most of that as rolling up in "engineering cost". Let me know if you can think of another column to add here to focus on "quality" of the dependencies.

ericstj and others added 2 commits November 18, 2025 13:52
Co-authored-by: Stephen Toub <stoub@microsoft.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants