derive_more: Deriving std Traits for Newtypes and Enums in Rust
Some more derive(Trait) options
At a glance
- What is it?
- derive_more fills the gap left by the standard derive macro set, letting newtype structs and enums keep Add, Display, From, Error and roughly three dozen other trait implementations without hand-written boilerplate. The trade-off is a feature-gated crate whose macro expansions you should inspect before trusting them.
- Who is it for?
- Adopt derive_more if you write newtype wrappers or enums that need std trait implementations and you are willing to enable features one by one in Cargo.toml. Skip it if you need constructor logic beyond a plain new, or if you already depend on a different derive macro crate for the same traits.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 8 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The boilerplate problem derive_more targets
Rust implements Add, Not, From and Display for its primitive types. Wrap an i32 in a struct and those implementations disappear, because the compiler has no way to know which field should receive the operation. The README frames this as the cost of the newtype pattern, and that framing is accurate: MyInt(i32) is a distinct type with no arithmetic, no formatting and no conversion into i32 until someone writes the impls by hand. For a single wrapper that is a page of mechanical code. For a codebase that uses newtypes to separate user IDs from order IDs from raw integers, it is a recurring tax.
The crate's audience is therefore narrow but deep. It is for Rust developers who already accept newtypes as a design tool and want the trait surface that the standard library gives to the wrapped type. It is not a general macro toolkit, and it does not attempt to replace hand-written implementations where the semantics are non-obvious. The README's own example shows the intended scale: a three-field Point2D gains From and Into, a newtype gains From, Add and PartialEq, and an enum gains From, Add and Display, all from a single derive attribute per type.
What actually gets generated for a struct or enum
The README is explicit that understanding the generated code matters, and it links to per-trait documentation explaining what each derive emits. One documented rule is that derives are independent: #[derive(Mul)] does not imply Div, and the README states you must write #[derive(Mul, Div)] to get both. That rule applies across the trait groups, so the attribute list is the full specification of behaviour.
The trait set is organized into groups. Conversion traits cover From, Into, FromStr, TryFrom, TryInto, IntoIterator, AsRef and AsMut. Formatting covers Debug plus a Display-like family that includes Binary, Octal, LowerHex, UpperHex, LowerExp, UpperExp and Pointer. Error-handling is a single Error derive. Operator overloading is the largest group: Index, Deref, Not-like (Not and Neg), Add-like (Add, Sub, BitAnd, BitOr, BitXor), Mul-like (Mul, Div, Rem, Shr, Shl), Sum-like (Sum and Product), IndexMut, DerefMut, AddAssign-like and MulAssign-like, plus Eq and PartialEq. Hash sits in its own category. Four derives produce static methods rather than trait impls: Constructor, IsVariant, Unwrap and TryUnwrap.
Formatting attributes are visible in the README example. An enum variant can carry #[display("int: {_0}")], and the example asserts that MyEnum::Int(15).to_string() equals "int: 15". A variant without a display attribute falls back to its field, since MyEnum::Uint(42) stringifies to "42". A unit-like variant can take a literal, as #[display("nothing")] does. The {_0} placeholder refers to the first field, which is a convention the crate defines rather than standard Rust formatting.
Feature flags decide what compiles
The installation section states that no derives are supported by default, and that each type of derive must be enabled as a feature in Cargo.toml. The README gives three configurations. The selective form is derive_more = { version = "2", features = ["from", "add", "into_iterator"] }. The blanket form is features = ["full"]. For no_std targets the README instructs default-features = false, noting that the only default feature is std, and that this can be combined with full.
The motivation given is compilation time: fewer enabled features mean less code to compile. That is a real cost model, but it puts a burden on the consumer. Adding a derive to a type requires editing Cargo.toml as well as the source file, and the failure mode when you forget is a compile error about an unresolved derive macro rather than a runtime surprise. The default-features = false path matters for embedded and other no_std work, and the README treats std as the sole default, so disabling it is a clean switch.
Import hygiene is a separate concern the README addresses at length. Derives are imported from the crate root by default, and use derive_more::derive::* imports all macros only. A with_trait module re-exports the standard library traits alongside the derives, so use derive_more::with_trait::Display brings both the derive macro and core::fmt::Display into scope. The README also documents a re-export pitfall: macros expand to absolute derive_more::* paths, so a downstream crate that only sees a re-exported macro fails with "could not find derive_more in the list of imported crates" unless the module itself is re-exported too.
Inspecting expansions and the minimum toolchain
Because the crate generates trait implementations you did not write, the README points to cargo-expand as the way to see the exact code produced for a specific type. That is the practical verification step: expand the type, read the impls, and confirm the field selection and semantics match your intent. This matters most for the operator groups, where a wrong choice of field would silently change arithmetic behaviour, and for Display, where the format string attributes determine output.
The README badge states Rust 1.81 and later as the supported compiler range. That is a hard floor for adoption, and it is worth checking against your project's minimum supported Rust version before adding the dependency. The crate also advertises that unsafe is forbidden, linking to the safety-dance project, which is a statement about the crate's own source rather than about the code its macros generate in your crate.
Where derive_more is the wrong tool
The README itself concedes a boundary. The Constructor derive produces a new method, and the README calls it "very basic", directing readers who need more customization to the derive-new crate. If your constructor needs validation, defaulting, multiple named constructors or fallible construction, Constructor is not the feature you want, and the README says so rather than overselling it.
A second limitation is structural: derives are independent, so the attribute list grows with each trait you need. A type that wants arithmetic, comparison, hashing, formatting and conversion ends up with a long derive line, and every addition is a deliberate act. That is arguably a feature, since nothing is implemented by accident, but it means the crate does not reduce the cognitive load of deciding which traits a type should have. It only removes the code once you have decided.
The third case is semantic. Deriving Add for a newtype maps the operation onto the inner value, which is correct for numeric wrappers and wrong for types where addition has domain rules, such as saturating arithmetic, checked arithmetic or unit-carrying quantities. The README does not discuss such cases, and the material gives no guidance on when a derived operator would be incorrect. That judgement is left entirely to the reader, and it is the main reason to expand the generated code before relying on it.
Alternatives and how their approach differs
The README names derive-new as the alternative for constructor generation, with the stated difference that derive_more's Constructor is basic and derive-new is where you go for more customization. That is a direct comparison from the source material: same problem area, different depth of control over the generated constructor.
For the trait derives themselves, the material does not name a competing crate, so any comparison beyond this point would be speculation. What can be said from the repository description is that derive_more's scope is broad by design, covering conversion, formatting, error handling, operators, hashing and static methods in one crate with per-trait feature flags. A narrower alternative would cover one group and require a separate dependency for the rest. The trade-off is between one dependency with many optional features and several dependencies with fixed scope, and the README's feature-flag design leans toward the former while trying to keep compilation cost proportional to what you enable.
Maintenance, versioning and licence
The repository is not archived and shows a push in September 2026. The recent release list covers v2.1.1 in December 2025, v2.1.0 earlier that month and v2.0.1 in February 2025. The README's installation examples all target version 2, and the major version boundary between 1.x and 2.x is not described in the supplied material, so anyone upgrading from a 1.x line should read the release notes rather than assume the derive syntax is unchanged.
The licence is MIT, as stated in the repository metadata and in the README badge. MIT is permissive and imposes no copyleft obligation on your code, but this is a description of the licence identifier, not legal advice, and the terms that matter for your organisation are in the LICENSE file itself. The dependency is a proc-macro crate, which means it runs at compile time in your build environment, and the feature flags determine how much of it is compiled. That is the ongoing cost to weigh: a compile-time dependency whose surface you control through Cargo.toml.
Editorial conclusion
Adopt derive_more if you write newtype wrappers or enums that need std trait implementations and you are willing to enable features one by one in Cargo.toml. Skip it if you need constructor logic beyond a plain new, or if you already depend on a different derive macro crate for the same traits. Before committing, run cargo expand on the specific type and check the generated impls, and confirm that your minimum supported Rust version is at least 1.81.
Community notes