Best Practice For Library Crate Dependency Version Numbers

I've got a Rust library crate and I'm trying to decide what the best practice for me would be when specifying the versions of my dependencies.

I'm leaning towards using the two digit ( i.e. 1.2 ) specifier for all dependencies.

Here's my understanding of Cargo's handling of versions:

  • 1.2.3 is equivalent to ^1.2.3
  • 1.2 is equivalent to 1.2.0
  • 1 is equivalent to 1.0.0
  • ^1.2.3 means that it will never use a version older than 1.2.3, but may use a version that has either a later minor version or later bugfix version.

In light of that, I see using two digit specifiers as saying in english:

I want to make sure I have this crate, with at least the given feature release, possibly any later feature releases, and any bugfix release.

That seems like a good balance.

If I wanted to be more explicit and correct with my version definitions I could either:

  1. Make it more specific, by making sure I don't need a specific bugfix version of the dependency for my library to work, and adding the third digit to the dependency.
  2. Make it more general, by making sure I actually need the feature version that I specified, and possibly decrementing that version, if my library can work without the features added in that version.

But I don't want to spend the time to verify the versions that meticulously right now, so I think just specifying the latest two-digit specifier for a crate at the time I add the dependency, and whenever I update my dependencies is a reasonable middleground.

Does that sound right?

Ideally, you should specify the minimum dependency version which you need and test your crate with minimal dependency versions generated using cargo update -Z minimal-versions. Of course, using the latest version of a dependency is fine as well, if you do not want to commit resources to additional testing. But I wouldn't call it "best practice".

3 Likes

For crates that differentiate between minor and patch releases, this approach makes sense. However there are some crates that just use patch releases for everything even if they are not 0.x.

Interesting, I haven't heard of that flag before. Thanks for bringing it up!

I might do that, though it's recommended against usage in the Cargo docs:

It is not recommended to use this feature. Because it enforces minimal versions for all transitive dependencies...

They're working on one that only operates on the direct dependencies, though, it sounds like.

Hmm, that would breach semver, though, wouldn't it? I suppose in that case I just have to be aware of those dependencies and treat them differently.

I agree with testing with the nightly/unstable -Z minimal-versions. That gives you best assurance that the versions you specify actually work. However, you'll find that others have made mistake in specifying too-low version requirements (like serde = "1"), and your dependencies can break with minimal-versions.

So the second-best and easier solution is to require always the latest version. Bump the versions at the beginning of your development cycle, so by the time you release your crate these deps won't be cutting edge. But meanwhile, you will be developing and testing with the versions you actually specify.

Yes, and it exists now: -Z direct-minimal-versions. I tried testing with -Z minimal-versions and this was very fragile; now I use -Z direct-minimal-versions in CI and it has given me no trouble.

1 Like

Perfect, I'll work that into my CI workflow.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.