[tool] table in Cargo.toml

NOTE: the exact spellings in this post are up for bikeshedding, take all the names used here as merely examples to convey my point.


My typical rust project has roughly three files solely for one or two lines of configuration: clippy.toml, rustfmt.toml, rust-toolchain.toml.

I think a nice QoL change would be the ability to specify them in Cargo.toml:

[tool.clippy]
key = true

[tool.rustfmt]
key = true

[tool.rustup]
channel = "default"

Alternatively, "first party" tools (rustup, rustfmt, clippy, etc) can get their own namespace (top or under a different table) instead of living in tool.$NAME and the tool namespace can be delegated to the community.

If you've used Python before, you'll realize this is something that already exists there. Python delegated a tool table to the community in pyproject.toml and to avoid name collisions, tools must use their PyPI name (both PyPI and crates.io have a flat namespace, so names are required to be unique).

Let's take ruff, the python linter written in rust, as an example. It supports configuration in ruff.toml and [tool.ruff] in pyproject.toml, with the former taking precedence if both are present. The advantage here is that I can put one or two lines of configuration in pyproject.toml or move it to ruff.toml if the configuration is too complex to avoid cluttering pyproject.toml. I find this to be an excellent approach and something I would love to have in my rust projects.

I'll also admit that none of this is deal breaking. I can continue living with a few extra files in my repositories but I'll also be happier to get rid of them :smiley: .


Here's an example that's a mix of tool, toolchain, and rustup.components table. As always, these are up for bikeshedding but I figured a real example would be nice regardless.

[package]
name = "cosmic_widget"
version = "0.1.0"
edition = "2024"
authors = ["Captain Nebula <nebula@starfleet.com>"]
description = "A widget that explores the vastness of your data."
repository = "https://github.com/captain-nebula/cosmic_widget"
license = "MIT OR Apache-2.0"

[dependencies]
glitter = "0.4"
data_compass = { version = "1.2", features = ["interstellar"] }

[toolchain]
channel = "nightly"
components = [ "rustfmt", "clippy" ]
profile = "minimal"

[rustup.components.clippy]
deny = ["suspicious", "whimsical"]
allow = ["lint_ranger::silly_names"]

[rustup.components.rustfmt]
max_line_length = 100

[tool.stardust-analyzer]
threshold_warning = 42
secret_key = "shhh_its_a_secret"

[tool.code-polisher]
language_flavor = "rust_with_sprinkles"
optimization_level = "ludicrous_speed"

Since recently you can configure lints in your manifest file.

Theoretically there is nothing stopping tools from reading their configuration from the [package.metadata] table, like i.e. docs.rs does. So in my opinion, the manifest file format already has what is needed. Tools like rustup, rustfmt, ruff, etc. would have to read their configuration from said table, which is something each tool would have to decide for themselves, if they want to extend their search for configuration to your manifest.

As far as I'm aware, [lints] and clippy.toml aren't identical. For example, I cannot specify avoid-breaking-exported-api = false in [lints].

1 Like

This does seem to be functionally identical to the tool table, but the wording seems to imply that's it's specifically for packaging rather than arbitrary developer tools that are irrelevant to the end user.

This section can be used for tools which would like to store package configuration in Cargo.toml.

I find this pretty generic. The whole section of the Cargo docs doesn't suggest to me that this is supposed to be used for packaging only, but that any tool you use for developing your package can use this table.