Rust has a compiler version and a language edition. Stable compilers are released every six weeks, and new versions keep compiling old code. An edition is an opt-in set of changes that would otherwise break existing code. At the time of writing, the latest release is Rust 1.99, and the latest edition is 2024 (The Rust Edition Guide).
How editions work
- An edition is chosen per crate, with
edition = "2024"inCargo.toml, orrustc --edition=2024. If neither is given, the edition is 2015. - Crates of different editions can be mixed in one program.
- Every new compiler supports every edition. An edition can change keywords, lexing, parsing and some semantics.
cargo fix --editionrewrites code to move to the next edition. Each edition has its own prelude.
| Edition | First compiler | Released |
|---|---|---|
| 2015 | Rust 1.0 | 15 May 2015 |
| 2018 | Rust 1.31 | 6 December 2018 |
| 2021 | Rust 1.56 | 21 October 2021 |
| 2024 | Rust 1.85 | 20 February 2025 |
Rust 1.0 and edition 2015
Rust 1.0 was released on 15 May 2015, and is the start of Rust’s stability guarantee. Edition 2015 is the name given later to the language as it was before edition 2018. It is still the default when no edition is set, and code can only be moved away from it.
Compared with later editions, in 2015 use paths are relative to the crate
root, extern crate is required, and async, await
and try are ordinary identifiers. dyn is a weak keyword, and
trait objects may be written without it. Anonymous parameters are allowed in trait
methods.
Edition 2018
Theme: productivity. First available in Rust 1.31.
| Change | Effect |
|---|---|
| Path and module system | Paths resolve uniformly in use and elsewhere. Crate names are in scope without extern crate. crate:: refers to the current crate. foo.rs can sit next to a foo/ folder, so mod.rs is no longer required |
| New keywords | async, await and dyn are strict keywords, and try is reserved |
| Anonymous trait parameters | Trait function parameters must be named |
| Raw pointer method dispatch | tyvar_behind_raw_pointer becomes a hard error |
| Cargo | A [[bin]] or [lib] section no longer disables auto-discovery of other targets |
Edition 2021
First available in Rust 1.56.
| Change | Effect |
|---|---|
| Prelude | TryFrom, TryInto and FromIterator are added |
| Cargo feature resolver | edition = "2021" implies resolver = "2" |
IntoIterator for arrays | array.into_iter() yields values instead of references |
| Closures | Closures capture disjoint fields, not whole variables |
| Panic macros | panic! always takes a format string |
| Reserved prefixes | prefix#ident, prefix"…" and prefix'c' are reserved |
| Raw lifetimes | 'r#ident becomes a single lifetime token |
| Hard errors | Bare trait objects (without dyn) and ... range patterns become errors |
| Or-patterns in macros | $x:pat matches top-level |; $x:pat_param keeps the old behaviour |
| C string literals | c"…" and cr"…" (stable since Rust 1.77) |
Edition 2024
First available in Rust 1.85 on 20 February 2025.
| Area | Change |
|---|---|
| RPIT lifetime capture | Return-position impl Trait captures all in-scope generic parameters by default; use<…> restricts this |
if let temporary scope | Temporaries of the scrutinee are dropped before else runs |
| Tail expression temporaries | Dropped before the block’s locals |
| Let chains | && chains of let in if and while are allowed; stable since Rust 1.88, edition 2024 only |
| Match ergonomics reservations | Writing mut, ref, ref mut, & or &mut is allowed only under a fully explicit prefix. See Binding modes |
Unsafe extern blocks | extern blocks must be written unsafe extern; items may be marked safe or unsafe |
| Unsafe attributes | export_name, link_section and no_mangle must use #[unsafe(…)] |
unsafe_op_in_unsafe_fn | Warns by default: unsafe operations in unsafe fn need an unsafe block |
static mut references | The static_mut_refs lint is deny by default |
| Never type fallback | The fallback for ! is ! rather than () |
| Macro fragments | expr also matches const and _ expressions, and expr_2021 keeps the old behaviour. A missing fragment specifier is an error |
| Keywords and tokens | gen is reserved. #"foo"# and ## are reserved |
| Standard library | Future and IntoFuture are in the prelude. Box<[T]> has IntoIterator by value. std::env::set_var, remove_var and CommandExt::before_exec are unsafe |
| Cargo | edition = "2024" implies resolver = "3", which considers rust-version. Duplicate spellings such as dev_dependencies are removed |
| Rustdoc and rustfmt | Doctests are combined into a single binary. style_edition can be set separately from the parsing edition |
Notable language additions by release
These features arrived in ordinary releases and work in every edition unless noted. Only selected releases are listed.
| Rust | Year | Addition |
|---|---|---|
| 1.0 | 2015 | First stable release |
| 1.13 | 2016 | The ? operator |
| 1.15 | 2017 | Custom derive macros |
| 1.26 | 2018 | impl Trait, match ergonomics, ..=, 128-bit integers |
| 1.27 | 2018 | dyn Trait, SIMD intrinsics |
| 1.30 | 2018 | Attribute and function-like procedural macros, raw identifiers |
| 1.31 | 2018 | Edition 2018, const fn, non-lexical lifetimes (edition 2018) |
| 1.36 | 2019 | alloc crate, MaybeUninit, non-lexical lifetimes for edition 2015 |
| 1.39 | 2019 | async and .await |
| 1.51 | 2021 | Const generics, in their first form |
| 1.53 | 2021 | Nested or-patterns, Unicode identifiers |
| 1.56 | 2021 | Edition 2021 |
| 1.58 | 2022 | Captured identifiers in format strings |
| 1.63 | 2022 | Scoped threads |
| 1.65 | 2022 | Generic associated types, let else |
| 1.75 | 2023 | async fn and return-position impl Trait in traits |
| 1.77 | 2024 | C string literals |
| 1.79 | 2024 | const blocks, associated type bounds |
| 1.80 | 2024 | Exclusive range patterns, LazyLock |
| 1.81 | 2024 | #[expect] lint level, core::error::Error |
| 1.82 | 2024 | &raw, precise capturing with use<…>, unsafe extern blocks, unsafe attributes |
| 1.85 | 2025 | Edition 2024, async closures |
| 1.86 | 2025 | Trait upcasting |
| 1.88 | 2025 | Let chains (edition 2024), naked functions |
| 1.95 | 2026 | if let guards, cfg_select! |