HackerReposA FIELD GUIDE TO OPEN SOURCE
ProSponsor the shelf♧ 0
← Back to top all-time
dtolnay
semver-trick
Rust2018–2026
dtolnay / semver-trick

semver-trick

How to avoid complicated coordinated upgrades

12Distinct people
13Mentions
0Explicit recommenders
573GitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

How to avoid complicated coordinated upgrades

GitHub

Where it is used

No documented product use was verified in the last source check.

What people are saying

No recommendation phrase was found in the indexed comments.

No classified warning is attached to this page. Read the discussions before treating silence as approval.

Also in these discussions

No other repository is repeatedly linked in the same discussions.

This week on Hacker News

Nov 7–Nov 14 UTC · Direct repository links and separately labeled related project stories. Indexed through 11/14/2026, 3:56:07 PM UTC.

Semver Trick direct repository link

Read the discussion on HN. A full-thread summary is not available yet.

Mentions over time

HN mentions by year13 dated mentions

Observed mentions: 2018-02-23 15:48:52 UTC to 2026-04-13 19:11:33 UTC.

0123452018-01-01 00:00:00 UTC to 2019-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments20182019-01-01 00:00:00 UTC to 2020-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2020-01-01 00:00:00 UTC to 2021-01-01 00:00:00 UTC (exclusive): 1 mentions; 1 submissions, 0 comments2021-01-01 00:00:00 UTC to 2022-01-01 00:00:00 UTC (exclusive): 5 mentions; 2 submissions, 3 comments2022-01-01 00:00:00 UTC to 2023-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments20222023-01-01 00:00:00 UTC to 2024-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2024-01-01 00:00:00 UTC to 2025-01-01 00:00:00 UTC (exclusive): 2 mentions; 1 submissions, 1 comments2025-01-01 00:00:00 UTC to 2026-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2026-01-01 00:00:00 UTC to 2027-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments. Incomplete calendar period.2026*

* An incomplete calendar period is marked with an outlined bar. Its count is not directly comparable with a full period.

Counts come from the repository’s dated source evidence. Index cutoff: 2026-11-02 08:16:59 UTC.

View mention counts and date ranges
UTC ranges include their start and exclude their end. Select a period to filter the source evidence.
PeriodStart (UTC)End (exclusive, UTC)MentionsSubmissionsComments
20182018-01-01 00:00:00 UTC2019-01-01 00:00:00 UTC101
20192019-01-01 00:00:00 UTC2020-01-01 00:00:00 UTC000
20202020-01-01 00:00:00 UTC2021-01-01 00:00:00 UTC110
20212021-01-01 00:00:00 UTC2022-01-01 00:00:00 UTC523
20222022-01-01 00:00:00 UTC2023-01-01 00:00:00 UTC101
20232023-01-01 00:00:00 UTC2024-01-01 00:00:00 UTC101
20242024-01-01 00:00:00 UTC2025-01-01 00:00:00 UTC211
20252025-01-01 00:00:00 UTC2026-01-01 00:00:00 UTC101
2026 (partial)2026-01-01 00:00:00 UTC2027-01-01 00:00:00 UTC101

What Hacker News says

13 sources
> If version 0.7 turned out to hit the right API and not require backward incompatible changes, releasing a version 1.0 would be as disruptive as a major version change Nope, this is what the semver trick is for: https://github.com/dtolnay/semver-trick TL;DR: You take the 0.7 library, release it as 1.0, then make a 0.7.1 release that does nothing other than depend on 1.0 and re-export all its items. Tada, a compatible 1.0 release that 0.7 users will get automatically when they upgrade. Even more interesting is that you can use this to coordinate only partially-breaking changes, e.g. if you have 100 APIs in your library but only make a breaking change to one, you can re-export the 99 unbroken APIs and only end up making breaking changes in practice for users who actually use the one API with breaking changes.
In Servo is now available on crates.io
> All of the versions need to align to pass `Regex` between yourself and your dependencies. In nominally typed languages, all types have to be nominally the same, yes, but it does not follow that semver compatible packages will not permit passing different versions of each around: https://github.com/dtolnay/semver-trick (the trick is to ensure that different versions have nominally the same type by forward dependency). Anyways, even with this, cargo has a lock file because you want to run in CI what you ran when you developed the feature instead of getting non-deterministic executions in an automated build + verification. That's what a deterministic build is aiming for. Then next feature you develop you can ignore the lockfile, pull in the new dependencies and move on with life because you don't necessarily care for determinism there: you
Read the rest
are willing to fix issues. Or you aren't and you use the lockfile.
In We shouldn't have needed lockfiles
No. It's a problem because you can only have one version of any given package in your dependency tree. You can't have `foo 2` and `foo 3` in your dependency tree. Without that limitation, there is a release valve of sorts where you can incur two different semver incompatible releases of the same package in your dependency tree in exchange for a working build. The hope is that it would be transitory state until all of your dependencies migrate. Rust, for example, has precisely this same problem, except that it is limited to public dependencies. For example, if `serde 2` were ever to be published, then there would likely be a period of immense pain where, effectively, everyone needs to migrate all at once. Even though `serde 1` and `serde 2` can both appear in the same dependency tree (unlike in Python), because it is a public dependency, e
Read the rest
veryone needs to be using the same version of the library or else the `Serialize` trait from `serde 1` will be considered distinct from the `Serialize` trait (or whatever) in `serde 2`. But if I, say published a `regex 2.0.0` tomorrow, then folks could migrate at their leisure. The only downside is that you'd have `regex 1` and `regex 2` in your dependency tree. Potentially for a long time until everyone migrated over. But your build would still work because it is uncommon for `regex` to be a public dependency. (Rust does have the semver trick[1] available to it as another release valve of sorts.) This problem is definitely not because of missing interfaces or whatever. [1]: https://github.com/dtolnay/semver-trick
In Should you use upper bound version constraints?
Let's say crate B depends on crate A with a pinned dependency, and uses one of its types in a public interface. Crate C depends on them both. It now can't bring in updates to A until B does, and when B updates that's a breaking change, so it better bump its major version. Take a look at this trick, for example, for foundational crates updating their major version: https://github.com/dtolnay/semver-trick Now imagine that being an issue every single patch update.
In Making Rust supply chain attacks harder with Cackle
> My project will still get 1.0.2, so it will still have the security hole. Right. To mitigate that you would regularly run `npm audit` or even just `npm upgrade` – and test afterwards of course. I'm not completely sold, but I do think it's a very interesting idea. > Can I ask for a warning if I'm getting two different versions linked into the same binary? Yes. That was the lint I linked in my last post. Alternatively, you can run `cargo tree --duplicates`. > "I really, really don't think think you should be using 1.0 any more" That's called "yanking". Personally I think it has limited usefulness, but it exists. https://doc.rust-lang.org/cargo/commands/cargo-yank.html > And what happens if both versions get pulled in, but the package in question uses an external data file whose format changed between 1.0 and 1.1? If it uses something like
Read the rest
`include!`, both copies will be compiled in (and maybe optimized later by the linker). If it's truly "external" like hosted on some website outside the package manager, then it just means the author broke their package. Maybe I misunderstood your question. > one of my dependencies constructs a foo using X 1.0, is that value of a different type than a foo constructed by X 1.1? I believe they are always different types. Cargo encourages but doesn't enforce semver, so anything can change between versions, including private fields or enum variants behind non_exhaustive, etc. So they're treated as different and you need to convert between them. Although this might only be true for major versions; I don't know off the top of my head. To work around it you can convert the types at crate boundaries, or the package author can use the so-called "semver trick" [1] [1]: https://github.com/dtolnay/semver-trick
In What NPM should do to stop a new colors attack
The JVM is 114MiB on my machine. A near-minimal ggez program in debug mode is about 100MiB,¹ and ggez is small for a Rust application library. When you start getting into the 300s of dependencies (i.e. every time I've ever got beyond a trivial desktop application), you're lucky if your release build is less than 100MiB. Sure, I could probably halve that by forking every dependency so they aren't duplicating versions, but that's a lot of work. (It's a shame Rust doesn't let you do conditional compilation based on dependency versions, or this would be a lot easier. As it is, we have to resort to the Semver trick: https://github.com/dtolnay/semver-trick/ — not that many people do that, so it's functionally useless.) Take GanttProject as an example. It's 20.6MiB of files, plus the JVM. I challenge any of you to make a Rust version (with acces
Read the rest
sibility support in the GUI) that can open (something resembling) its XML files and draw some (vague graphical Proof of Concept) representation on the screen (with editable text fields), in less than 114+21=135 MiB of binary. And then tell me how, because I've been trying to do that kind of thing for over a year. ¹: I can get it down to around 8MiB with release mode, lto etc., but that significantly increases the build time and only about halves the weight of the intermediate build files.
In The chip shortage keeps getting worse – why can't we just make more?
There's been a lot of attention given to this in Rust: - Defining semver requirements for the ecosystem: https://stackoverflow.com/questions/41185023/what-exactly-is... - There's also a library that attempts to automatically check sermver adherence of a crate: https://github.com/rust-lang/rust-semverver - And there has been quite a bit of effort into preventing semver requirements from fracturing the ecosystem. This revolves around the compiler working with multiple major versions of a single library: https://github.com/dtolnay/semver-trick
In Semantic Versioning Will Not Save You

MAKE YOURSELF AT HOME

A few shortcuts

/
Search the collection
?
Open this guide
Esc
Close dialogs and navigation

Your saved repositories and interests stay in this browser.