Rust 2024 Edition
Edition System
The Rust Edition system is an opt-in, per-crate versioning mechanism (edition = "2015" | "2018" | "2021" | "2024" in Cargo.toml) that allows the Rust language, standard library prelude, Cargo dependency resolver, and rustfmt style rules to make backward-incompatible syntax and ergonomic improvements every three years without ever splitting the crate ecosystem.
+-------------------------------------------------------------------+
| Rust Compiler (`rustc 1.85+`) |
| |
| Crate A (`edition = "2015"`) ---+ |
| Crate B (`edition = "2018"`) ---+--> Lowered to Unified HIR/MIR! |
| Crate C (`edition = "2021"`) ---+ Linked into ONE Binary! |
| Crate D (`edition = "2024"`) ---+ |
+-------------------------------------------------------------------+
How the Edition System Prevents Ecosystem Splits
Unlike Python 2 vs Python 3 (where a Python 3 application could not directly import a Python 2 library), Rust editions exist only at the surface parsing, macro, prelude, and lint levels of each individual crate:
- Once
rustcparses a crate's source files according to its declarededitionand lowers them into High-level and Mid-level Intermediate Representations (HIR/MIR), all editions are identical inside the compiler. - A Rust 2024 binary crate can depend on a Rust 2015, 2018, or 2021 library crate—and vice versa—with zero friction.
- Most new Rust features (such as new standard library APIs,
constgenerics, orasynctraits) are released on all editions simultaneously in regular 6-week compiler releases. Editions are reserved exclusively for changes that would break existing code if enabled silently (such as reserving a new keyword likegen, changing lifetime capture defaults, or promoting warnings to errors).
Evolution of Rust Editions (2015 to 2024)
| Edition | Stabilized In | Key Milestones Introduced |
|---|---|---|
2015 |
rustc 1.0 (2015) |
Initial stable release; default edition if edition key is omitted from Cargo.toml. |
2018 |
rustc 1.31 (2018) |
Reserved async/await keywords, simplified module system (no extern crate), Non-Lexical Lifetimes (NLL), dyn Trait syntax. |
2021 |
rustc 1.56 (2021) |
Disjoint closure field capture, IntoIterator for [T; N] arrays by value, TryFrom/TryInto/FromIterator in prelude, Cargo Resolver v2. |
2024 |
rustc 1.85 (2025) |
RPIT lifetime capture of all in-scope lifetimes + use<..> syntax, unsafe extern blocks, #[unsafe(no_mangle)], unsafe fn set_var, reserved gen keyword, Future/IntoFuture in prelude, Temporary Lifetime Extension refinements, Cargo MSRV-aware Resolver v3, merged doc-test binaries. |
Selecting an Edition in Cargo.toml and rustc
[package]
name = "modern_service"
version = "0.1.0"
edition = "2024"
When invoking rustc directly without Cargo, pass --edition=2024:
// Future and IntoFuture are included directly in the Rust 2024 prelude
// without requiring `use std::future::{Future, IntoFuture};`!
fn accepts_future<F: Future<Output = u32>>(fut: F) -> F {
fut
}
fn main() {
let _f = accepts_future(async { 42 });
println!("Compiled with Rust 2024 prelude (`Future` in scope automatically)");
}
Compiled with Rust 2024 prelude (`Future` in scope automatically)