You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I am new to both derive_more and derive_where, so the only thing I could do was to run AI on both and generate this. Could you add some guideline which should be used when? I believe only the authors of the crates can tell if this is accurate or not. I'm including it here for everyone's reference (and to save some dup AI re-run energy :) ), but I have no clue if this is good.
Executive Summary
Both derive_more and derive_where are Rust proc‐macro crates that reduce boilerplate for #[derive]. derive_more (MIT license, owner JelteF) provides many custom derive macros for standard traits (e.g. Add, From, Display, Error, etc.) and associated helper methods (e.g. Constructor). It’s widely used (millions of downloads) and actively maintained (last release v2.1.1 on Dec 22, 2025【71†L534-L540】【44†L220-L222】). derive_where (MIT/Apache-2.0, owners ModProg and daxpedda) offers a single attribute #[derive_where(...)] that mimics #[derive] but without automatically inserting generic bounds. This lets you derive traits (Clone, Debug, Default, PartialEq, Eq, Ord, Hash, optionally Serde Serialize/Deserialize, etc.) for types with generics without requiring those generics to implement the traits【57†L98-L101】【24†L332-L340】. Its latest stable version is 1.6.1 (released Mar 13, 2026【50†L201-L204】). In practice, use derive_more when you need to auto-implement a variety of traits on newtypes or enums (e.g. numeric ops, conversions, error formatting), and use derive_where when you need more flexible generic trait bounds on derives. The sections below compare their traits/macros, APIs, compatibility, performance and community metrics in detail.
Crate Overviews
derive_more: “Some more derive(Trait) options” – provides #[derive(...)] macros for many common traits (conversions, formatting, operators, error handling, etc.) and static helpers like Constructor. Maintained by JelteF, latest version 2.1.1 (Dec 22, 2025)【54†L4-L10】【71†L534-L540】, license MIT【54†L4-L10】, repo github.com/JelteF/derive_more【54†L11-L15】. Last commit (v2.1.1) was Dec 22, 2025【71†L534-L540】【44†L220-L222】. It requires Rust 1.81+ and supports no_std (via a default “std” feature that can be disabled)【54†L81-L88】【41†L601-L608】.
derive_where: “Attribute proc-macro to simplify deriving standard and other traits with custom generic type bounds”【57†L98-L101】. Maintained by ModProg (owner ModProg, also daxpedda), latest stable 1.6.1 (released Mar 13, 2026)【50†L201-L204】, license MIT OR Apache-2.0【57†L9-L13】, repo github.com/ModProg/derive-where【57†L11-L13】. The last tagged release 1.6.1 was Mar 13, 2026【50†L201-L204】. It supports deriving Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash out-of-the-box, plus Serialize/Deserialize via feature flags, and Zeroize (with optional “zeroize” feature)【24†L332-L341】. It works in no_std by default【24†L364-L370】 and requires Rust 1.57+ (MSRV 1.57)【24†L385-L393】. It is essentially a single attribute macro with options for skipping fields, specifying bounds, enum defaults, etc.
Both crates are actively maintained (recent releases, CI, etc). derive_more has 2.1k★ stars, 146 forks【71†L534-L540】 and is transitively depended on by ~218k crates【71†L560-L563】, indicating broad usage. derive_where has more modest adoption (89★, 7 forks【73†L179-L180】) and ~7.3k dependent crates (search results), but it solves a narrower problem.
Derive Macros & Features Comparison
The table below summarizes each crate’s key derive macros/attributes, their behavior, supported item types (structs/enums), and a typical code example. Where derive_more groups similar derives, we list representative macros.
Macro / Feature
Behavior / Implementations
Supported Items
Example Usage
derive_more::From
Implements From<Inner> for tuple structs or enum variants, enabling type conversion.
For each enum variant, derives an is_variant() method.
Enums
#[derive(IsVariant)] enum E { A, B } // impl E::is_a(&self) -> bool, etc.
derive_more::Unwrap / TryUnwrap
For enums, derives unwrap_variant() and fallible versions.
Enums
#[derive(Unwrap)] enum E { A(i32), B } // impl E::unwrap_a()
derive_where(attribute)
Like #[derive(...)] but omits requiring generic trait bounds: generates impls for any type parameters. Traits supported include Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash plus optionally Serde Serialize/Deserialize and Zeroize (with features)【24†L332-L341】. It also supports skipping fields/variants for certain traits.
#[derive_where(Clone, Debug)] struct S<T>(T); // impl Clone for all T【56†L108-L113】. Optionally: #[derive_where(Clone, Debug; T: Clone)] to bind T: Clone【56†L132-L140】.
Notes: The derive_more macros must be enabled via Cargo features (e.g. "derive_more = { version = "2", features = ["add", "from", ...] }"【43†L476-L484】) to avoid long compile times. By default it only provides macros (not the trait imports) unless you use the with_trait module. In contrast, derive_where is a single proc-macro attribute; you write #[derive_where(...)] much like #[derive], with optional arguments after a semicolon to specify bounds【56†L130-L138】【56†L168-L171】. derive_where also offers field- or variant-level options #[derive_where(skip)], #[derive_where(skip_inner)], and #[derive_where(incomparable)] to exclude fields from generated impls【56†L184-L193】【24†L371-L379】.
The key overlap is that both can derive Debug, Clone, Eq/PartialEq, etc., but they do so differently: derive_more implements the trait only when you specify it (with any needed generic bounds), whereas derive_where always omits generic bounds (so #[derive_where(Clone)] never requires T: Clone, whereas #[derive(Clone)] would). Many derive_more traits have no direct analogue in derive_where (e.g. arithmetic, conversion traits, Display/Error, static methods). Conversely, derive_where’s special features (custom bounds, skip behavior) have no match in derive_more.
API & Ergonomics
Import/Usage: derive_more macros are imported like other custom derives: e.g. use derive_more::{Add, From, Display}【54†L98-L100】. You must enable each group as a feature. If you only need a few traits, compile-time is reduced by enabling fewer features. By default no derives are supported unless features are turned on【43†L453-L462】. In no_std contexts you disable the default std feature【43†L466-L474】. derive_where is an attribute on a type: #[derive_where(...)] struct S<T>(T);【56†L108-L113】. You only add derive-where = "1" to Cargo.toml (it has no feature flags besides optional serde/zeroize). Multiple #[derive_where] attributes can stack (e.g. #[derive_where(Clone)] #[derive_where(Debug)])【56†L115-L123】, and you can qualify the crate name if renamed. Overall its API is simpler (one macro with options) but less granular.
Trait Bounds Handling: This is the main design difference. derive_where by default generates impls without any T: Trait bounds, whereas normal Rust derive and derive_more’s derive macros only derive impls when the generics satisfy the trait. For example, #[derive_where(Clone)] struct S<T>(T); implements Clone for all T, by effectively calling Default::default() for skipped fields or ignoring them. You can add custom bounds after a semicolon: #[derive_where(Clone; T: Clone)] will bind T: Clone【56†L132-L140】. derive_more’s derives generally infer bounds on the struct’s type parameters automatically (as of v2.1.0, they do so “structurally” for operator traits)【41†L603-L609】. derive_more also allows specifying custom error types for some derives (FromStr, TryInto can specify error)【41†L593-L601】.
Compile-time: derive_more can become heavy if many features are enabled. Its documentation explicitly advises enabling only needed derive types to speed up compilation【43†L453-L462】. derive_where is relatively lightweight (one attribute macro), and you pay cost only for the traits you list. In both cases, using tools like cargo expand can reveal generated code【22†L346-L354】. The generated code patterns differ: derive_more’s macros often forward to the wrapped field (e.g. impl Add for S(T) does { S(self.0.add(rhs.0)) }), whereas derive_where’s code usually calls Self::default() or ignores fields when generics are not bounded. Error messages can differ: derive_more’s macro errors generally point to missing type implementations or misuse of attributes; derive_where errors often occur if you misuse skip options or specify impossible bounds. No major complaints appear in issue trackers about poor error clarity.
Ergonomics: derive_more’s usage can be more verbose due to multiple derives and feature flags. It has helpful auto-completion for many traits. derive_where’s single attribute is convenient for cases where many traits need no-bounds derives. derive_where’s options for skipping fields/groups (e.g. skip, skip_inner, named skip groups) provide fine-grained control that derive_more does not. For enum defaults, derive_where adds support for #[derive_where(default)] on a variant (enabled by Rust 1.62)【57†L172-L180】, something derive_more doesn’t address.
Compatibility & Ecosystem
Both crates support modern Rust editions (2018/2021/2024) and are on crates.io. derive_more targets MSRV 1.81 (per docs)【54†L50-L54】; derive_where supports MSRV 1.57 (CI checks)【24†L385-L393】. derive_more’s macros generally work in no_std (if you disable the default std feature)【43†L466-L474】, and derive_where is no_std by default【24†L364-L370】.
Interactions with Other Crates:
serde: derive_where explicitly supports Serde via an optional serde feature to derive Serialize/Deserialize without bounds【24†L338-L345】. derive_more does not provide serde derives (you’d use serde::Serialize), but it coexists fine; you can use both on a struct if needed (#[derive(Serialize)] #[derive_more::Display] etc).
thiserror/anyhow: derive_more’s improved Display and Error aims to replace thiserror for error types【39†L699-L708】. For example, #[derive(Display, Error)] can format error messages with attributes similarly to thiserror, and uses a real Error type for sources (instead of a &'static str)【39†L699-L708】. derive_where has no notion of Error/Display on enums (it’s trait-agnostic).
Other crates: derive_more re-exports many traits so it doesn’t conflict with trait imports【43†L419-L428】. derive_where is trait-neutral and simply generates impls; it can be used alongside any other derives (including those from serde, derivative, educe, etc). Some users combine them: e.g. #[derive_more(Add)] #[derive_where(Clone)] is valid. There are no known compatibility issues reported.
Performance & Benchmarks
We found no published benchmarks directly comparing these macros. Anecdotally, enabling only needed derive_more features mitigates compile slowdown. derive_where’s GitHub README claims it avoids using unsafe code unless a safe feature is disabled【24†L369-L378】. Users have not reported significant performance issues unique to either crate. (General guidance: procedural macros do add compile time, but both are reasonably optimized.)
Community & Maintenance
Metric
derive_more
derive_where
Stars (GitHub)
2.1k【71†L534-L540】
89【73†L179-L180】
Forks
146【71†L542-L544】
7【73†L179-L180】
Issues Open
70【70†L12-L15】
12【73†L185-L187】
PRs Open
12【70†L12-L15】
1【73†L185-L187】
Latest Release
2.1.1 (Dec 22, 2025)【71†L534-L540】
1.6.1 (Mar 13, 2026)【50†L201-L204】
Downloads (crates.io)
~hundreds of millions (all-time)
~38 million (all-time)
Used by (GitHub)
~218k repos【71†L560-L563】
~7.3k (as noted on GitHub)
Notable issues/PRs
Many minor fixes and features (custom error support, skip fields, etc)【41†L593-L601】【39†L612-L619】
Active development on skip/group fixes (e.g. “Clone skip group and Zeroize variant skip fix” v1.4.0)【69†L239-L244】; some closed PRs on enum support.
derive_more is very popular and actively maintained (releases in late 2025 for v2.x). Its issue tracker shows active community contributions (bug fixes, feature requests like better generics support【41†L603-L610】). derive_where has less traffic but also regular releases (v1.6.0 in Aug 2025, v1.6.1 Mar 2026) and a focus on correctness (e.g. verifying Rust’s enum discriminants). Issue volume is low (≈12 open) and appears manageable.
Migration & Usage Guidance
When to use which crate:
Use derive_where if you need to derive standard traits without forcing generic bounds. For example, to implement Clone/Debug/Eq on a generic wrapper and not require T: Clone, write:
This generates impl<T> Clone for Wrapper<T> (no T: Clone bound)【56†L108-L113】. By contrast, #[derive(Clone)] alone would require T: Clone. If you later need a specific bound, you can add it after a semicolon: #[derive_where(Clone; T: Clone)].
Use derive_more when you need other traits (e.g. mathematical ops, conversions, Display, etc.) on simple structs/enums. For example:
use derive_more::{From,Add,Display};#[derive(PartialEq,From,Add,Display)]structMyInt(i32);
This makes MyInt::from(i32), Add (so you can add MyInt), and Display::to_string() work as expected【22†L311-L320】. derive_more cannot derive Clone for a generic type without bounds, so it complements derive_where in many cases.
Often both can coexist: e.g. on a struct with generics, you might write: #[derive_more(Add, From)] #[derive_where(Clone, Debug)]. That applies trait derives from derive_more and a separate derive_where attribute. Just be careful to import the macros (use derive_more::{...}; use derive_where::derive_where;).
Example (equivalent impls): Consider an enum with a generic:
enumE<T>{A(T),B}// With derive_more:#[derive(PartialEq,Eq)]// requires T: PartialEq/EqenumE1<T:PartialEq>(T,T);// With derive_where:#[derive_where(PartialEq,Eq)]// no T bound by defaultenumE2<T>(T,T);
Here E1<T> needs T: PartialEq + Eq, whereas E2<T> (derive_where) works for anyT. If desired, you can have both: #[derive_where(PartialEq; T)] #[derive_more(PartialEq)] to emulate the standard derive.
Pitfalls: derive_more’s wide trait list means it can inflate your API surface; only enable needed features to avoid long build times. derive_where’s free-for-all derivation can be surprising: it might implement Eq even when it semantically shouldn’t, so use skip if you want to exempt certain fields from equality【56†L184-L193】. Also, derive_where does not support union derives except Clone/Copy【24†L352-L358】.
Security, Licensing, Stability
Security: Both crates are mature and widely used; no known security vulnerabilities are reported. derive_more’s code is essentially just delegating to safe trait impls, and derive_where’s default path is safe (it avoids unsafe unless a “nightly” feature is enabled)【24†L369-L378】. Always review auto-generated impls if security-sensitive (e.g. Zeroize usage in derive_where).
Licensing: derive_more is MIT (per [54†L4-L10]), whereas derive_where is dual-licensed MIT/Apache-2.0【57†L9-L13】. Both are permissive and compatible with commercial use.
API Stability: derive_more v2 adheres to semver; however, its changelog shows occasional breaking changes in major releases (e.g. v2.0.0 had breaking changes to import style)【39†L719-L727】. Most users will stick to a specific minor version if MSRV is a concern【54†L81-L90】. derive_where increments minor versions when MSRV changes【24†L385-L393】. Both crates document breaking changes (see their CHANGELOGs).
Decision Flowchart
flowchart TB
A[Need automatic derives for types?] --> B{Require custom generic bounds?}
B -->|Yes| C[Use derive_where for traits like Clone, Debug, Eq]
C --> D{Also need other traits?}
D -->|Yes| E[Combine with derive_more for ops/conversions]
D -->|No| F[derive_where alone suffices]
B -->|No| G{Need many auto-derived traits?}
G -->|Yes| H[Use derive_more (enable needed features)]
G -->|No| I[Use standard #[derive] or other crate]
H --> J{Need to avoid generic bounds?}
J -->|Yes| E
J -->|No| H
Loading
This chart summarizes typical choices: if you only need to sidestep generic bounds on standard traits, go with derive_where (and you can optionally still use derive_more for others). If you want a broad set of auto-derives (e.g. arithmetic, conversions, Display, Error), use derive_more. In some cases, both will be applied to cover all needs.
Sources: Official crate docs and READMEs were used for descriptions and feature lists【54†L98-L100】【57†L98-L101】【24†L332-L341】【22†L311-L320】. Version, license, and repository info come from docs.rs and GitHub【57†L9-L13】【54†L4-L10】【50†L201-L204】【71†L534-L540】. Community metrics are from GitHub repository pages【71†L534-L540】【73†L179-L180】【69†L165-L173】 and download stats from crates.io. Relevant discussions and change logs provided details on API changes【39†L719-L727】【41†L603-L609】.
I am new to both
derive_moreandderive_where, so the only thing I could do was to run AI on both and generate this. Could you add some guideline which should be used when? I believe only the authors of the crates can tell if this is accurate or not. I'm including it here for everyone's reference (and to save some dup AI re-run energy :) ), but I have no clue if this is good.Executive Summary
Both derive_more and derive_where are Rust proc‐macro crates that reduce boilerplate for
#[derive]. derive_more (MIT license, owner JelteF) provides many custom derive macros for standard traits (e.g.Add,From,Display,Error, etc.) and associated helper methods (e.g.Constructor). It’s widely used (millions of downloads) and actively maintained (last release v2.1.1 on Dec 22, 2025【71†L534-L540】【44†L220-L222】). derive_where (MIT/Apache-2.0, owners ModProg and daxpedda) offers a single attribute#[derive_where(...)]that mimics#[derive]but without automatically inserting generic bounds. This lets you derive traits (Clone, Debug, Default, PartialEq, Eq, Ord, Hash, optionally SerdeSerialize/Deserialize, etc.) for types with generics without requiring those generics to implement the traits【57†L98-L101】【24†L332-L340】. Its latest stable version is 1.6.1 (released Mar 13, 2026【50†L201-L204】). In practice, use derive_more when you need to auto-implement a variety of traits on newtypes or enums (e.g. numeric ops, conversions, error formatting), and use derive_where when you need more flexible generic trait bounds on derives. The sections below compare their traits/macros, APIs, compatibility, performance and community metrics in detail.Crate Overviews
derive_more: “Some more derive(Trait) options” – provides
#[derive(...)]macros for many common traits (conversions, formatting, operators, error handling, etc.) and static helpers likeConstructor. Maintained by JelteF, latest version 2.1.1 (Dec 22, 2025)【54†L4-L10】【71†L534-L540】, license MIT【54†L4-L10】, repo github.com/JelteF/derive_more【54†L11-L15】. Last commit (v2.1.1) was Dec 22, 2025【71†L534-L540】【44†L220-L222】. It requires Rust 1.81+ and supportsno_std(via a default “std” feature that can be disabled)【54†L81-L88】【41†L601-L608】.derive_where: “Attribute proc-macro to simplify deriving standard and other traits with custom generic type bounds”【57†L98-L101】. Maintained by ModProg (owner ModProg, also daxpedda), latest stable 1.6.1 (released Mar 13, 2026)【50†L201-L204】, license MIT OR Apache-2.0【57†L9-L13】, repo github.com/ModProg/derive-where【57†L11-L13】. The last tagged release 1.6.1 was Mar 13, 2026【50†L201-L204】. It supports deriving
Clone,Copy,Debug,Default,Eq,PartialEq,Ord,PartialOrd,Hashout-of-the-box, plusSerialize/Deserializevia feature flags, andZeroize(with optional “zeroize” feature)【24†L332-L341】. It works inno_stdby default【24†L364-L370】 and requires Rust 1.57+ (MSRV 1.57)【24†L385-L393】. It is essentially a single attribute macro with options for skipping fields, specifying bounds, enum defaults, etc.Both crates are actively maintained (recent releases, CI, etc). derive_more has 2.1k★ stars, 146 forks【71†L534-L540】 and is transitively depended on by ~218k crates【71†L560-L563】, indicating broad usage. derive_where has more modest adoption (89★, 7 forks【73†L179-L180】) and ~7.3k dependent crates (search results), but it solves a narrower problem.
Derive Macros & Features Comparison
The table below summarizes each crate’s key derive macros/attributes, their behavior, supported item types (structs/enums), and a typical code example. Where derive_more groups similar derives, we list representative macros.
From<Inner>for tuple structs or enum variants, enabling type conversion.#[derive(From)] struct MyInt(i32); // allows MyInt::from(5)【43†L311-L319】Into<Inner>for types (complement ofFrom).#[derive(Into)] struct Pnt { x: i32, y: i32 } // (x,y).into() gives (x,y)#[derive(TryFrom)].#[derive(TryFrom)] enum N { #[try_from(i)] I(i32), U(u32) }std::str::FromStr(parsing) based on enum variant names or pattern.#[derive(FromStr)] enum Color { Red, Blue }IntoIteratorby delegating to inner.#[derive(IntoIterator)] struct Wrapper(Vec<i32>); for x in Wrapper(v) { ... }as_ref()/as_mut()to inner type for newtype structs.#[derive(AsRef, AsMut)] struct W(String); let s: &String = W("hi".into()).as_ref();Debugwith optional customization (new in v1.0.0)【39†L691-L700】.#[derive(Debug)] struct S(i32);Display(string formatting) with optional#[display("...")]syntax.#[display]attributes)#[derive(Display)] #[display("{_0:?}")] struct S(i32);Binary,LowerHex, etc. (sameDisplaymacro handles these).#[derive(Display)] #[display("{:x}", _0)] struct Hex(u32);std::error::Errorand optionallyDisplay::Errorsources.#[derive(Error, Display)] #[display("{msg}")] struct MyErr { msg: String }Index<Idx>for newtypes wrapping collections.#[derive(Index)] struct D(Vec<i32>); let x = D(vec![1,2])[0];Derefto inner type for wrapper newtypes.#[derive(Deref, DerefMut)] struct Wrap(String);!or unary-operators for numeric newtypes.#[derive(Not, Neg)] struct Flag(bool);Add,Sub,BitAnd,BitOr,BitXor(with_assignvariants) for newtypes.#[derive(Add, Sub)] struct MyInt(i32);Mul,Div,Rem,Shl,Shr(with_assignvariants).#[derive(Mul, DivAssign)] struct Factor(f64);SumorProductfor iterator-based accumulation.#[derive(Sum)] struct Tot(i64); let x: Tot = vec![Tot(1), Tot(2)].into_iter().sum();#[derive(PartialEq, Eq)] struct X(T);– new in 2.1.0, treats generics structurally【41†L580-L588】.fn new(field1, field2) -> Selfconstructor for structs.#[derive(Constructor)] struct P(x: i32, y: i32); // impl P::new(x,y)is_variant()method.#[derive(IsVariant)] enum E { A, B } // impl E::is_a(&self) -> bool, etc.unwrap_variant()and fallible versions.#[derive(Unwrap)] enum E { A(i32), B } // impl E::unwrap_a()#[derive(...)]but omits requiring generic trait bounds: generates impls for any type parameters. Traits supported includeClone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hashplus optionally SerdeSerialize/DeserializeandZeroize(with features)【24†L332-L341】. It also supports skipping fields/variants for certain traits.#[derive_where(Clone, Debug)] struct S<T>(T); // impl Clone for all T【56†L108-L113】. Optionally:#[derive_where(Clone, Debug; T: Clone)]to bindT: Clone【56†L132-L140】.Notes: The derive_more macros must be enabled via Cargo features (e.g.
"derive_more = { version = "2", features = ["add", "from", ...] }"【43†L476-L484】) to avoid long compile times. By default it only provides macros (not the trait imports) unless you use thewith_traitmodule. In contrast, derive_where is a single proc-macro attribute; you write#[derive_where(...)]much like#[derive], with optional arguments after a semicolon to specify bounds【56†L130-L138】【56†L168-L171】. derive_where also offers field- or variant-level options#[derive_where(skip)],#[derive_where(skip_inner)], and#[derive_where(incomparable)]to exclude fields from generated impls【56†L184-L193】【24†L371-L379】.The key overlap is that both can derive
Debug,Clone,Eq/PartialEq, etc., but they do so differently: derive_more implements the trait only when you specify it (with any needed generic bounds), whereas derive_where always omits generic bounds (so#[derive_where(Clone)]never requiresT: Clone, whereas#[derive(Clone)]would). Many derive_more traits have no direct analogue in derive_where (e.g. arithmetic, conversion traits,Display/Error, static methods). Conversely, derive_where’s special features (custom bounds, skip behavior) have no match in derive_more.API & Ergonomics
Import/Usage: derive_more macros are imported like other custom derives: e.g.
use derive_more::{Add, From, Display}【54†L98-L100】. You must enable each group as a feature. If you only need a few traits, compile-time is reduced by enabling fewer features. By default no derives are supported unless features are turned on【43†L453-L462】. Inno_stdcontexts you disable the defaultstdfeature【43†L466-L474】.derive_where is an attribute on a type:
#[derive_where(...)] struct S<T>(T);【56†L108-L113】. You only addderive-where = "1"to Cargo.toml (it has no feature flags besides optional serde/zeroize). Multiple#[derive_where]attributes can stack (e.g.#[derive_where(Clone)] #[derive_where(Debug)])【56†L115-L123】, and you can qualify the crate name if renamed. Overall its API is simpler (one macro with options) but less granular.Trait Bounds Handling: This is the main design difference. derive_where by default generates impls without any
T: Traitbounds, whereas normal Rust derive and derive_more’s derive macros only derive impls when the generics satisfy the trait. For example,#[derive_where(Clone)] struct S<T>(T);implementsClonefor allT, by effectively callingDefault::default()for skipped fields or ignoring them. You can add custom bounds after a semicolon:#[derive_where(Clone; T: Clone)]will bindT: Clone【56†L132-L140】. derive_more’s derives generally infer bounds on the struct’s type parameters automatically (as of v2.1.0, they do so “structurally” for operator traits)【41†L603-L609】. derive_more also allows specifying custom error types for some derives (FromStr,TryIntocan specify error)【41†L593-L601】.Compile-time: derive_more can become heavy if many features are enabled. Its documentation explicitly advises enabling only needed derive types to speed up compilation【43†L453-L462】. derive_where is relatively lightweight (one attribute macro), and you pay cost only for the traits you list. In both cases, using tools like
cargo expandcan reveal generated code【22†L346-L354】. The generated code patterns differ: derive_more’s macros often forward to the wrapped field (e.g.impl Add for S(T)does{ S(self.0.add(rhs.0)) }), whereas derive_where’s code usually callsSelf::default()or ignores fields when generics are not bounded. Error messages can differ: derive_more’s macro errors generally point to missing type implementations or misuse of attributes; derive_where errors often occur if you misuse skip options or specify impossible bounds. No major complaints appear in issue trackers about poor error clarity.Ergonomics: derive_more’s usage can be more verbose due to multiple derives and feature flags. It has helpful auto-completion for many traits. derive_where’s single attribute is convenient for cases where many traits need no-bounds derives. derive_where’s options for skipping fields/groups (e.g.
skip,skip_inner, named skip groups) provide fine-grained control that derive_more does not. For enum defaults, derive_where adds support for#[derive_where(default)]on a variant (enabled by Rust 1.62)【57†L172-L180】, something derive_more doesn’t address.Compatibility & Ecosystem
Both crates support modern Rust editions (2018/2021/2024) and are on crates.io. derive_more targets MSRV 1.81 (per docs)【54†L50-L54】; derive_where supports MSRV 1.57 (CI checks)【24†L385-L393】. derive_more’s macros generally work in
no_std(if you disable the defaultstdfeature)【43†L466-L474】, and derive_where isno_stdby default【24†L364-L370】.serdefeature to deriveSerialize/Deserializewithout bounds【24†L338-L345】. derive_more does not provide serde derives (you’d useserde::Serialize), but it coexists fine; you can use both on a struct if needed (#[derive(Serialize)] #[derive_more::Display]etc).DisplayandErroraims to replacethiserrorfor error types【39†L699-L708】. For example,#[derive(Display, Error)]can format error messages with attributes similarly to thiserror, and uses a realErrortype for sources (instead of a&'static str)【39†L699-L708】. derive_where has no notion ofError/Displayon enums (it’s trait-agnostic).#[derive_more(Add)] #[derive_where(Clone)]is valid. There are no known compatibility issues reported.Performance & Benchmarks
We found no published benchmarks directly comparing these macros. Anecdotally, enabling only needed derive_more features mitigates compile slowdown. derive_where’s GitHub README claims it avoids using unsafe code unless a
safefeature is disabled【24†L369-L378】. Users have not reported significant performance issues unique to either crate. (General guidance: procedural macros do add compile time, but both are reasonably optimized.)Community & Maintenance
Cloneskip group andZeroizevariant skip fix” v1.4.0)【69†L239-L244】; some closed PRs on enum support.derive_more is very popular and actively maintained (releases in late 2025 for v2.x). Its issue tracker shows active community contributions (bug fixes, feature requests like better generics support【41†L603-L610】). derive_where has less traffic but also regular releases (v1.6.0 in Aug 2025, v1.6.1 Mar 2026) and a focus on correctness (e.g. verifying Rust’s enum discriminants). Issue volume is low (≈12 open) and appears manageable.
Migration & Usage Guidance
When to use which crate:
Use derive_where if you need to derive standard traits without forcing generic bounds. For example, to implement
Clone/Debug/Eqon a generic wrapper and not requireT: Clone, write:This generates
impl<T> Clone for Wrapper<T>(noT: Clonebound)【56†L108-L113】. By contrast,#[derive(Clone)]alone would requireT: Clone. If you later need a specific bound, you can add it after a semicolon:#[derive_where(Clone; T: Clone)].Use derive_more when you need other traits (e.g. mathematical ops, conversions,
Display, etc.) on simple structs/enums. For example:This makes
MyInt::from(i32),Add(so you can addMyInt), andDisplay::to_string()work as expected【22†L311-L320】. derive_more cannot deriveClonefor a generic type without bounds, so it complements derive_where in many cases.Often both can coexist: e.g. on a struct with generics, you might write:
#[derive_more(Add, From)] #[derive_where(Clone, Debug)]. That applies trait derives from derive_more and a separatederive_whereattribute. Just be careful to import the macros (use derive_more::{...}; use derive_where::derive_where;).Example (equivalent impls): Consider an enum with a generic:
Here
E1<T>needsT: PartialEq + Eq, whereasE2<T>(derive_where) works for anyT. If desired, you can have both:#[derive_where(PartialEq; T)] #[derive_more(PartialEq)]to emulate the standard derive.Pitfalls: derive_more’s wide trait list means it can inflate your API surface; only enable needed features to avoid long build times. derive_where’s free-for-all derivation can be surprising: it might implement
Eqeven when it semantically shouldn’t, so useskipif you want to exempt certain fields from equality【56†L184-L193】. Also, derive_where does not support union derives except Clone/Copy【24†L352-L358】.Security, Licensing, Stability
unsafeunless a “nightly” feature is enabled)【24†L369-L378】. Always review auto-generated impls if security-sensitive (e.g.Zeroizeusage in derive_where).Decision Flowchart
flowchart TB A[Need automatic derives for types?] --> B{Require custom generic bounds?} B -->|Yes| C[Use derive_where for traits like Clone, Debug, Eq] C --> D{Also need other traits?} D -->|Yes| E[Combine with derive_more for ops/conversions] D -->|No| F[derive_where alone suffices] B -->|No| G{Need many auto-derived traits?} G -->|Yes| H[Use derive_more (enable needed features)] G -->|No| I[Use standard #[derive] or other crate] H --> J{Need to avoid generic bounds?} J -->|Yes| E J -->|No| HThis chart summarizes typical choices: if you only need to sidestep generic bounds on standard traits, go with derive_where (and you can optionally still use derive_more for others). If you want a broad set of auto-derives (e.g. arithmetic, conversions,
Display,Error), use derive_more. In some cases, both will be applied to cover all needs.Sources: Official crate docs and READMEs were used for descriptions and feature lists【54†L98-L100】【57†L98-L101】【24†L332-L341】【22†L311-L320】. Version, license, and repository info come from docs.rs and GitHub【57†L9-L13】【54†L4-L10】【50†L201-L204】【71†L534-L540】. Community metrics are from GitHub repository pages【71†L534-L540】【73†L179-L180】【69†L165-L173】 and download stats from crates.io. Relevant discussions and change logs provided details on API changes【39†L719-L727】【41†L603-L609】.