R
RUSTY YELLOW PAGES

#![feature(...)]Attribute


Explanation

#![feature(name)], an inner attribute at a crate root, opts the crate into an unstable compiler or language feature named name — some piece of not-yet-stabilized syntax, standard library API, or compiler capability that exists in the compiler's source but isn't part of stable Rust. Writing #![feature(...)] and building with the stable (or beta) toolchain is a hard compile error — this attribute only works at all on the nightly toolchain; it's the mechanism nightly-only Rust actually is, syntactically. There is no equivalent for stable code: either a capability has been stabilized, and needs no #![feature(...)] at all, or it hasn't, and using it requires nightly plus this attribute naming it explicitly.

This exists so the language and standard library can experiment: new syntax, new trait machinery, or a new core/std API can be implemented and used by real projects on nightly, gathering feedback, well before anyone commits to the (much harder to walk back) guarantee that comes with stabilizing it for stable Rust. A crate that uses #![feature(...)] is making a deliberate trade: access to capability that doesn't exist any other way yet, in exchange for opting out of Rust's usual stability guarantee for that specific piece of the language.

Here be dragons — read this before reaching for it. An unstable feature can change shape, gain new restrictions, or be removed outright between nightly releases without the deprecation cycle a stable API would get; code depending on one can simply stop compiling on a newer nightly with no advance warning. This makes #![feature(...)] fundamentally different from every other attribute on this wiki: it isn't just "advanced" or "niche," it's an explicit acknowledgment that the ground underneath the annotated crate can shift at any time, which is why it's essentially never seen in a published, stable-toolchain-targeting crate — almost every real-world user is either the standard library itself, compiler tooling, or a project that has specifically chosen to track nightly.

Usage examples

Enabling an unstable language feature on nightly

// Nightly-only — this attribute and the feature it names are not available on stable/beta.
#![feature(let_chains)]

fn describe(value: Option<i32>) -> &'static str {
    if let Some(n) = value && n > 0 {
        "positive"
    } else {
        "non-positive or absent"
    }
}

Designing a public API

A project deliberately tracks nightly Rust to use an unstabilized standard library API not available any other way, accepting the risk that a future nightly could change or remove it — framed honestly as a nightly-only choice, not something expected to reach every user's stable toolchain.

// Nightly-only. On stable/beta this line alone is a compile error naming
// the unknown feature; there is no stable equivalent to fall back to.
#![feature(step_trait)]

use std::iter::Step;

// Real usage would implement `Step` for a custom type to make it usable
// directly in a range expression (`MyType(0)..MyType(10)`) — an
// unstabilized capability at the time of writing, illustrative here.

Because unstable features carry no compatibility guarantee between nightly releases, a project reaching for #![feature(...)] is making a considered, ongoing maintenance commitment — tracking nightly, watching for breaking changes to the specific feature used, and being ready to adapt or drop the feature if it's altered before stabilizing; the Unstable Book documents each feature gate along with its current status for exactly this kind of ongoing risk assessment before depending on one.

Explanation

Embedded support: Full

#![feature(...)] itself works identically regardless of target — it's a toolchain-level gate, unaffected by std vs #![no_std]. The one point worth naming for embedded specifically: a handful of capabilities embedded code has wanted for a long time — improvements to asm!/global_asm! before they stabilized, certain const-generics refinements, niche core APIs — spent real time as nightly-only features, and embedded projects have, anecdotally, been slightly more willing than typical application code to track nightly and accept #![feature(...)]'s stability risk while waiting, simply because there's often no stable workaround for a capability that reaches directly into architecture-specific low-level code. This is a minor, project-by-project pattern, not a rule — plenty of embedded crates target stable exclusively, and the same "this can change without notice" caveat from the classic explanation applies without exception here too.

Usage examples

A firmware crate tracking nightly for an inline-asm improvement

// Nightly-only — illustrative of the kind of low-level feature embedded
// code has sometimes tracked nightly for before stabilization.
#![feature(asm_const)]

use core::arch::asm;

unsafe fn delay_cycles<const N: u32>() {
    asm!("1: subs {0}, {0}, #1", "bne 1b", inout(reg) N => _); // <- uses the const generic directly inside asm!
}