← Back to index
PR #3924Work-in-progress preview from an open pull request.View on GitHub ↗
REVIEW
#3924

cargo-hints-min-opt-level

Authorjoshtriplett
CreatedFeb 22 2026
UpdatedJul 14 2026
Rust Issue

Summary

Allow Rust library to provide a simple hint about the minimum opt-level to build them with.

Motivation

When people build Rust projects, they have a choice of tradeoffs between the speed of the build and the performance of the code at runtime. Builds using the dev profile aim for minimal build time at the expense of unoptimized code at runtime; builds using the release profile spend more time building in order to improve runtime performance.

However, there are some library crates for which almost every use case wants optimization, because an unoptimized build provides so little performance as to be unusable. Such libraries typically include a note in their README.md warning users to turn on optimization even in the dev profile:

[profile.dev.package."example-high-performance-package"]
opt-level = 3

This RFC adds a mechanism for crates to hint that builds should use optimization by default, while still allowing the top-level crate to easily override this. Handling this in dependencies makes it automatic for users, and also makes it easier to keep up with an evolving dependency tree.

Guide-level explanation

Some libraries benefit strongly from optimization, or are hurt especially by builds without optimization, to the point that they expect almost no users to ever want to run them unoptimized. Such libraries can use the Cargo hints system to provide a minimum optimization level:

[hints]
min-opt-level = 2

When building with a profile with a default optimization level lower than the hints.min-opt-level value, the crate will be built with the specified minimum optimization level instead. When building with a profile with a higher default optimization level, that higher optimization level will take precedence.

This applies whether the optimization level is the default for the profile, or is set by the user explicitly for the profile:

[profile.dev]
opt-level = 1
# Does not override a higher hints.min-opt-level specified in a dependency.

To override the hinted minimum optimization level, the top-level crate can use profile overrides to set the opt-level. Any opt-level specified via profile overrides will take precedence over any hint, whether the profile override applies to a specific crate or to all dependencies:

[profile.dev.package."*"]
opt-level = 1
# Overrides hints.min-opt-level specified in a dependency.

[profile.dev.package."random-package"]
opt-level = 0
# Overrides hints.min-opt-level specified in a dependency.

Note that setting opt-level = "s" or opt-level = "z" in the top-level crate's profile will override min-opt-level in a dependency, on the theory that crates optimizing for size are likely to want size-over-speed optimizations in their dependencies as well.

Reference-level explanation

The hints.min-opt-level key requires an integer, and only supports numeric hint levels (0, 1, 2, 3). Non-numeric hint levels like "s" and "z" are not supported, because they don't fit into a strictly ordered progression, and because they're more likely to be use-case-dependent and better determined by the top-level crate.

hints.min-opt-level, like any hint, does not affect a crate's MSRV; older versions of Cargo will ignore it.

Any profile override will take precedence over hint.min-opt-level, including an override for all dependencies, an override for all build dependencies, or an override for a specific dependency.

A profile specifying an opt-level will not override a higher hints.min-opt-level specified in a dependency.

Note that a hint provided by a given library crate only applies to that specific crate, not that package's dependencies. If the code that needs optimizing is in a dependency, that dependency would need to add the hint.

There are two primary reasons to use this hint:

  • The typical full build (not just an incremental build) will be sped up by optimizing the crate.
  • The crate is disproportionately affected by optimization, such that it may be unusably slow (many times slower) without optimization.

Drawbacks

Crates could overuse this mechanism, requiring optimization even when they don't actually need it. We should provide clear documentation recommending when to use it and when not to use it.

Even when used for the intended purpose, different users may have different tradeoffs. The override mechanism allows users to retain control, but the defaults will not be ideal for all users. The mechanism proposed by this RFC is making a deliberate tradeoff, and proposes that the defaults will work better for more users than the current default of not providing these hints, but this RFC does not claim the new default will be an improvement for every user.

If a crate using this mechanism wishes to nonetheless build with different optimizations within its own workspace, it would have to add an override.

Limitations

Library crates cannot set this for dependencies they do not maintain; a crate can only set the min-opt-level for itself. This may cause issues for crates whose performance depends heavily on its dependencies; such crates may still have to rely on user documentation.

Library optimizations may not apply to code inlined or monomorphized by a user's crate.

Rationale and alternatives

This mechanism intentionally does not offer a "maximum optimization level", nor does it support optimizing for size.

This mechanism intentionally does not provide access to any specific target feature flags, as this is typically something the top-level crate needs to retain full control over based on its minimum system requirements.

We could support multiple min-opt-level hints, one for dev-like profiles and one for release-like profiles, for crates that want a lower min-opt-level in the dev profile. However, profile.release already defaults to opt-level = 3, so min-opt-level will generally never affect the release profile, only the dev profile. Thus, a single setting seems sufficient.

We could have a simple boolean, e.g. optimize-in-dev = true, and leave it to Cargo whether that means opt-level 1, 2, or 3. This would be simpler, but would prevent crates from determining whether they benefit from opt-level 3 (e.g. aggressive vectorization and loop unrolling) or not.

We could support "z" or "s" somehow. This would be more complex and require more design, since those aren't on a linear scale like the numeric optimization levels. Furthermore, these seem less likely to be usefully determined by dependencies: whether a dependency will have massive performance issues if built without optimization is something the dependency may know, while the need for size optimization seems likely to be use-case-dependent and better set by the top-level crate. (The use of crates designed for embedded, for instance, does not necessarily indicate that the user is size-constrained and would prefer size optimizations.)

We could have a hint apply recursively to dependencies. This seems like more control than a library crate could have, as a dependency may be used in multiple places in the crate graph.

Prior art

Cargo already provides the profile overrides mechanism, for the top-level crate to specify the opt-level of individual crates.

This RFC builds on the hints mechanism, currently used for hints.mostly-unused. The post announcing hints.mostly-unused included a section on future hints such as min-opt-level. Cargo has an issue discussing min-opt-level.

C and C++ compilers provide directives such as #pragma optimize or __attribute__((optimize)), which let individual files or functions define an optimization level.

Unresolved questions

Should a profile with opt-level = "s" or opt-level = "z" override a dependency's min-opt-level? This RFC says it should, but sometimes users might not want that. We could also give more control over that.

Future possibilities

hints.min-opt-level is a simple mechanism providing a single hint. There are many other possible optimization hints a library might wish to provide, and we could consider adding further hints for those in the future. Any such hint would need to balance the tradeoffs between value, additional complexity, and whether crates in the ecosystem know the right optimization level for their crate better than their users do.

We could in particular have a max-opt-level, for crates that don't benefit from opt-level = 3 to lower the optimiation level to 2.

The mechanism to override a dependency's opt-level using profile.dev.package forces a given opt-level whether the dependency asks for higher or lower. Users of overrides, particularly those for "*", might want a mechanism for setting a minimum without overriding a higher optimization level.

We may in the future want to change the default optimization level for the dev profile to 1, rather than 0. opt-level 1 includes optimizations that can make compilation faster, such as by sending less code to the codegen backend (e.g. LLVM). This might reduce the number of crates motivated to use this mechanism, but the mechanism would remain important, as there are library crates which strongly benefit from opt-level 2 or 3.

We may want to provide a further mechanism for libraries whose performance depends heavily on their dependencies to optimize those dependencies.

We may want to provide a mechanism for libraries to optimize code inlined or monomorphized by a user's crate. That would likely require compiler enhancements.

We may want to surface this in a visible way for users to see that it has been applied to their dependencies. For instance, we could note it in --timings.