# Optional features are part of the crate — the project should say so

**URL:** <https://internals.rust-lang.org/t/optional-features-are-part-of-the-crate-the-project-should-say-so/24069>\
**Category:** cargo\
**Created:** [March 11, 2026, 12:55pm UTC](https://internals.rust-lang.org/t/optional-features-are-part-of-the-crate-the-project-should-say-so/24069 "2026-03-11T12:55:21Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![tomveens](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tomveens/32/14173_2.png) [@tomveens](https://internals.rust-lang.org/u/tomveens)\
**Post date:** [March 11, 2026, 12:55pm UTC](https://internals.rust-lang.org/t/optional-features-are-part-of-the-crate-the-project-should-say-so/24069/1 "2026-03-11T12:55:21Z")

</div>

When a crate defines an optional feature like `mock`, and there's a module behind `#[cfg(feature = "mock")]`, that code is part of the crate. It compiles. It’s tested. It’s documented. It’s not an afterthought — it’s intentional.

But when someone opens the project, that code is often grayed out. The file shows up as “not included in any crates.” Go-to-def doesn’t work. It’s as if it’s not there.

This isn’t because the code is optional. It’s because the project hasn’t said: _“This feature is meant to be used.”_

We already have a place for project-local intent: `.cargo/config.toml`. It’s where we set `RUSTFLAGS`, define targets, and configure environment variables. It’s version-controlled, shared, and respected by Cargo, build scripts, and tools.

And rust-analyzer already reads from it — whenever it sees `[env]`.

So it’s natural for it to also express: _“When analyzing this crate, these features are active.”_

```rust
# .cargo/config.toml
[unstable]
rust-analyzer.cargo.features = "all"

```

or

```rust
[unstable]
rust-analyzer.cargo.features = ["mock"]

```

This doesn’t change how `cargo build` works. It doesn’t affect compilation. It just aligns analysis with the project’s intent — the same way `[env]` already does.

No setup. No terminal tricks. No editor-specific files.

If a feature exists and is meant to be used, the project should be able to say so — once, clearly, in the same place we already use for project configuration.

We already have the mechanism. This is just using it.

---

<div class="post-metadata">

**Author:** ![jdahlstrom](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jdahlstrom/32/3351_2.png) [@jdahlstrom](https://internals.rust-lang.org/u/jdahlstrom)\
**Post date:** [March 11, 2026, 1:00pm UTC](https://internals.rust-lang.org/t/optional-features-are-part-of-the-crate-the-project-should-say-so/24069/2 "2026-03-11T13:00:31Z")

</div>

Was this post written by a LLM?

---

<div class="post-metadata">

**Author:** ![tomveens](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tomveens/32/14173_2.png) [@tomveens](https://internals.rust-lang.org/u/tomveens)\
**Post date:** [March 11, 2026, 1:11pm UTC](https://internals.rust-lang.org/t/optional-features-are-part-of-the-crate-the-project-should-say-so/24069/3 "2026-03-11T13:11:42Z")

</div>

No

---

<div class="post-metadata">

**Author:** ![epage](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/epage/32/3171_2.png) [@epage](https://internals.rust-lang.org/u/epage)\
**Post date:** [March 11, 2026, 1:43pm UTC](https://internals.rust-lang.org/t/optional-features-are-part-of-the-crate-the-project-should-say-so/24069/4 "2026-03-11T13:43:30Z")

</div>

rust-analyzer already has a configuration setting for controlling features, see [Configuration - rust-analyzer](https://rust-analyzer.github.io/book/configuration.html#cargo.features)

---

<div class="post-metadata">

**Author:** ![tomveens](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tomveens/32/14173_2.png) [@tomveens](https://internals.rust-lang.org/u/tomveens)\
**Post date:** [March 11, 2026, 1:54pm UTC](https://internals.rust-lang.org/t/optional-features-are-part-of-the-crate-the-project-should-say-so/24069/5 "2026-03-11T13:54:41Z")

</div>

Yes, but rust-analyzer is not looking into cargo config for it's own config key.

---

<div class="post-metadata">

**Author:** ![epage](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/epage/32/3171_2.png) [@epage](https://internals.rust-lang.org/u/epage)\
**Post date:** [March 11, 2026, 2:01pm UTC](https://internals.rust-lang.org/t/optional-features-are-part-of-the-crate-the-project-should-say-so/24069/6 "2026-03-11T14:01:58Z")

</div>

What benefit are you expecting by rust-analyzer reading `.cargo/config.toml`?

---

<div class="post-metadata">

**Author:** ![tomveens](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tomveens/32/14173_2.png) [@tomveens](https://internals.rust-lang.org/u/tomveens)\
**Post date:** [March 11, 2026, 2:15pm UTC](https://internals.rust-lang.org/t/optional-features-are-part-of-the-crate-the-project-should-say-so/24069/7 "2026-03-11T14:15:04Z")

</div>

The configuration is more directed to the editor. So we must use config files for each editor. I wish to version control that analysis can be done even over certain optional features. I don't the editor is using, I actually don't want to care. I do know that the rust-analyser is more important, and I don't like to setup over and over again for every editor. Rust-analyser does have the feature. They also already use the cargo config. I think it is a project specific setting and not a editor one. Keeps my git clean. 🙂And I stumbled upon it because, setting it in the zed editor did not work -\> so me thinking what could be better.

---

<div class="post-metadata">

**Author:** ![kpreid](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kpreid/32/8484_2.png) [@kpreid](https://internals.rust-lang.org/u/kpreid)\
**Post date:** [March 11, 2026, 2:36pm UTC](https://internals.rust-lang.org/t/optional-features-are-part-of-the-crate-the-project-should-say-so/24069/8 "2026-03-11T14:36:10Z")

</div>

Sometimes I need the view with a feature _disabled_, to ensure that the code is correct without it, especially in situations where the `cfg`s don't purely add code but switch from one implementation to another.

Therefore, I think that rust-analyzer (and other language tooling) should not treat the set of enabled features as _configuration_, but as _current editing state_. It should be [easy to toggle](https://github.com/rust-lang/rust-analyzer/issues/13596) without changing any files that might be in version control.

From this perspective, the thing that should go in config files is not “enable these features” but something like “_recommended_ ‘complete’ set of features”. I don’t know that this changes the proposed design at all, since if this Cargo config key existed it would presumably get overridden by `.vscode/settings.json` if present, but I thought it is worth mentioning.

---

<div class="post-metadata">

**Author:** ![pacak](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/pacak/32/11934_2.png) [@pacak](https://internals.rust-lang.org/u/pacak)\
**Post date:** [March 11, 2026, 3:32pm UTC](https://internals.rust-lang.org/t/optional-features-are-part-of-the-crate-the-project-should-say-so/24069/9 "2026-03-11T15:32:45Z")

</div>

You can add something like in your `Cargo.toml`

```toml
[dev-dependencies]
mycrate = { path = ".", features = ["stuff", "disabled", "by", "default"] }

```

and rust-analyzer picks those features. You'll probably need them enabled anyway if you want to add any tests.

Also configuration for rust-analyzer can go not only into editor specific files but also into `rust-analyzer.toml` sitting in a project root - doc mentions that the support is somewhat spotty though. I imagine they would take a pull request adding some support that is missing.

---

<div class="post-metadata">

**Author:** ![tomveens](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tomveens/32/14173_2.png) [@tomveens](https://internals.rust-lang.org/u/tomveens)\
**Post date:** [March 11, 2026, 3:49pm UTC](https://internals.rust-lang.org/t/optional-features-are-part-of-the-crate-the-project-should-say-so/24069/10 "2026-03-11T15:49:20Z")

</div>

It is up to the project maintainer to do a suggestion. It indeed feels very important for a user to override it with the editors config. It is perfect for that.

---

<div class="post-metadata">

**Author:** ![epage](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/epage/32/3171_2.png) [@epage](https://internals.rust-lang.org/u/epage)\
**Post date:** [March 11, 2026, 4:12pm UTC](https://internals.rust-lang.org/t/optional-features-are-part-of-the-crate-the-project-should-say-so/24069/11 "2026-03-11T16:12:32Z")

</div>

Not finding the issue right now but this can get confusing results in some cases.

This also makes it more difficult to test without features which can be important in some cases.

---

<div class="post-metadata">

**Author:** ![tomveens](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tomveens/32/14173_2.png) [@tomveens](https://internals.rust-lang.org/u/tomveens)\
**Post date:** [March 11, 2026, 6:57pm UTC](https://internals.rust-lang.org/t/optional-features-are-part-of-the-crate-the-project-should-say-so/24069/12 "2026-03-11T18:57:54Z")

</div>

That is touching testing, but I was thinking about just developing. Optional features like mock, tracing or serde would not be handled by rust-analyzer. That is not always the reflection of the crate's intent.

---

<div class="post-metadata">

**Author:** ![tomveens](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tomveens/32/14173_2.png) [@tomveens](https://internals.rust-lang.org/u/tomveens)\
**Post date:** [March 11, 2026, 9:57pm UTC](https://internals.rust-lang.org/t/optional-features-are-part-of-the-crate-the-project-should-say-so/24069/13 "2026-03-11T21:57:50Z")

</div>

For the second part. The `rust-analyzer.toml` file seems to me like a more user-specific config you can add to `.gitignore`. Some rust-analyzer config looks more like project- or workspace-specific suggestions from a project maintainer. When rust-analyzer also reads them from `.cargo/config.toml`, it can be part of that shared crate.

---

<div class="post-metadata">

**Author:** ![kpreid](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kpreid/32/8484_2.png) [@kpreid](https://internals.rust-lang.org/u/kpreid)\
**Post date:** [March 11, 2026, 10:38pm UTC](https://internals.rust-lang.org/t/optional-features-are-part-of-the-crate-the-project-should-say-so/24069/14 "2026-03-11T22:38:31Z")

</div>

> [@pacak](#):
>
> You can add something like in your `Cargo.toml`
> 
> ```rust
> [dev-dependencies]
> mycrate = { path = ".", features = ["stuff", "disabled", "by", "default"] }
> 
> ```

> [@epage](#):
>
> Not finding the issue right now but this can get confusing results in some cases.
> 
> This also makes it more difficult to test without features which can be important in some cases.

A more flexible way to get this same effect today is to add another package in the same workspace which has this dependency. Then, builds using the default set of workspace members will have the features, and `cargo test -p mycrate` will not.

But it might not be desirable to apply the features to all default-members builds, only editing. So, it might make sense for Cargo to offer a feature list, not as a config, but as a _workspace_ property or properties — some sort of `workspace.default-features-for-development`. This would have the advantage over config that the features apply exactly to the workspace (which is the scope at which feature names mean something) rather than the current directory.

---

<div class="post-metadata">

**Author:** ![tomveens](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tomveens/32/14173_2.png) [@tomveens](https://internals.rust-lang.org/u/tomveens)\
**Post date:** [March 12, 2026, 10:30am UTC](https://internals.rust-lang.org/t/optional-features-are-part-of-the-crate-the-project-should-say-so/24069/15 "2026-03-12T10:30:23Z")

</div>

A hint from cargo.toml for rust-analyzer can be used to include optional features. But for that to make sense it should also benefit Cargo, and I don't know enough about Cargo's design to say if that's justified.

Rust-analyzer already has the ability to read project settings. It respects [env] from `.cargo/config.toml`. Though I believe it does so through Cargo, not by parsing the file directly (Somebody might confirm this). Since work on rust-analyzer support is experimental (could not make it work yet), it would make it easier to also read their own keys from `.cargo/config.toml`. The experiment does give me the idea that there is a demand for project-level config. I think my proposal is also an addition to the rust-analyzer config file.

In general, I think of it this way:

- Project intent -\> shared defaults `.cargo/config.toml`
- User preference -\> local settings `rust-analyzer.toml`
- Editor choice -\> editor-specific settings (e.g. `.vscode/`, `.zed/`)

All three can be version controlled separately if preferred.

Project-level config could go in `rust-analyzer.toml`, but then there's no clean distinction between a crate's suggestion and a user preference. As rust-analyzer already uses [env] from `.cargo/config.toml`, it makes sense to also use it to set defaults. Using a cargo config also works in workspaces.

---

<div class="post-metadata">

**Author:** ![kpreid](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kpreid/32/8484_2.png) [@kpreid](https://internals.rust-lang.org/u/kpreid)\
**Post date:** [March 12, 2026, 4:12pm UTC](https://internals.rust-lang.org/t/optional-features-are-part-of-the-crate-the-project-should-say-so/24069/16 "2026-03-12T16:12:28Z")

</div>

> [@tomveens](#):
>
> A hint from cargo.toml for rust-analyzer can be used to include optional features. But for that to make sense it should also benefit Cargo, and I don't know enough about Cargo's design to say if that's justified.

I think that `default-features-for-development` would benefit Cargo workflows, too. In particular, if `cargo test` enabled those features by default, then `cargo test` without arguments would be closer to “test everything reasonable”, instead of the status quo of not testing anything that’s an optional feature not enabled by anything in the workspace.

---

<div class="post-metadata">

**Author:** ![mathstuf](https://avatars.discourse-cdn.com/v4/letter/m/958977/32.png) [@mathstuf](https://internals.rust-lang.org/u/mathstuf)\
**Post date:** [March 12, 2026, 5:07pm UTC](https://internals.rust-lang.org/t/optional-features-are-part-of-the-crate-the-project-should-say-so/24069/17 "2026-03-12T17:07:31Z")

</div>

I do _not_ like that behavior because I have CI do `cargo test --frozen --locked` to test exactly what is built. I would be quite unhappy if I would have to "fight" some defaults that differ from `build` behaviors.

---

<div class="post-metadata">

**Author:** ![Vorpal](https://avatars.discourse-cdn.com/v4/letter/v/aca169/32.png) [@Vorpal](https://internals.rust-lang.org/u/Vorpal)\
**Post date:** [March 12, 2026, 10:14pm UTC](https://internals.rust-lang.org/t/optional-features-are-part-of-the-crate-the-project-should-say-so/24069/18 "2026-03-12T22:14:30Z")

</div>

Shouldn't CI test also at least with no features and with all festures?

---

<div class="post-metadata">

**Author:** ![robofinch](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/robofinch/32/13874_2.png) [@robofinch](https://internals.rust-lang.org/u/robofinch)\
**Post date:** [March 12, 2026, 11:32pm UTC](https://internals.rust-lang.org/t/optional-features-are-part-of-the-crate-the-project-should-say-so/24069/19 "2026-03-12T23:32:40Z")

</div>

I prefer to use `cargo hack test --feature-powerset` (with `--include-features` and `--exclude-features` as needed, e.g. for platform-specific or platform-incompatible features).

I also overrode `rust-analyzer.check.overrideCommand` in `.vscode/settings.json` to a program that makes (and caches) several calls to `cargo hack clippy --feature-powerset --depth 1`. The result is that all errors, from any tested `cfg` combination, are overlaid. However, it's not enough for go-to-def or type hints... `cfg`-d out code still gets grayed out as normal.

I think the ideal would be for rust-analyzer to support overlaying results from multiple sets of `cfg`s, targets, and so on without having to use third-party workarounds. (I fear the cost in RAM usage might be high, but then again, my `check.overrideCommand` does a pretty bad job of caching stuff and still works fine.)

---

<div class="post-metadata">

**Author:** ![mathstuf](https://avatars.discourse-cdn.com/v4/letter/m/958977/32.png) [@mathstuf](https://internals.rust-lang.org/u/mathstuf)\
**Post date:** [March 13, 2026, 2:55am UTC](https://internals.rust-lang.org/t/optional-features-are-part-of-the-crate-the-project-should-say-so/24069/20 "2026-03-13T02:55:47Z")

</div>

Yes, I have multiple sets of jobs for such cases. Each job set uses a `CARGO_FEATURES` to set the flags to use for each, so I expect `build` and `test` to behave similarly for the same set of flags.

[Next page](https://internals.rust-lang.org/t/optional-features-are-part-of-the-crate-the-project-should-say-so/24069.md?page=2)
