---
title: How to use derive_more crate in Rust derive macros
summary: Add derive_more to Cargo.toml with required features and apply the derive macro to your struct to auto-generate trait implementations.
lang: en
slug: how-to-use-derivemore-crate-in-rust-derive-macros
published: 2026-04-17T12:05:42+00:00
updated: 2026-04-25T22:00:13+00:00
canonical: https://www.rustfaq.org/en/how-to-use-derivemore-crate-in-rust-derive-macros/
---

# How to use derive_more crate in Rust derive macros



## When boilerplate steals your focus

You are building a wrapper around a third-party type. Maybe a `Config` struct that holds a `HashMap` and some metadata. You want to treat your `Config` like a `HashMap` so you can call `.get()` and `.insert()` without typing `self.0` or writing a dozen forwarding methods. You start writing `impl Deref for Config`, then `impl DerefMut`, then `impl From<Config> for HashMap`, then `impl Display`. Your editor fills with repetitive code that does nothing but delegate. You realize you are spending more time writing glue than logic.

The `derive_more` crate exists to kill that boilerplate. It provides derive macros that generate standard trait implementations based on your struct or enum layout. You add `#[derive(Deref, From, Display)]` to your type, and the macro writes the impl blocks for you. It handles the boring parts: dereferencing to a field, converting from a variant, formatting fields, implementing `Error` chains. You keep the structure. The macro fills in the behavior.

Stop writing delegation by hand. Let the compiler generate it.

## What derive_more actually does

`derive_more` is a procedural macro crate. When you apply a derive attribute, the macro runs during compilation, inspects your type definition, and emits Rust code. It does not guess. It follows strict rules based on your type layout. For a tuple struct with one field, it assumes that field is the target. For a named struct with multiple fields, it requires you to mark the target with an attribute like `#[deref]`.

Think of it like a specialized stamp press. You feed it your type definition. It reads the shape, applies the correct trait template, and prints the exact `impl` block you would have written. The difference is speed and consistency. You avoid typos in trait signatures. You avoid forgetting to forward a method. You keep your source file focused on domain logic instead of plumbing.

The crate is modular. You enable only the traits you need via feature flags in `Cargo.toml`. This keeps compile times low and avoids pulling in unused dependencies. The community convention is to list features explicitly. A blanket `derive_more = "2"` works but drags in everything, which slows down your build. Be specific.

```toml
[dependencies]
# Enable only the features you use. This reduces compile time.
derive_more = { version = "2", features = ["deref", "from", "display", "error"] }
```

The macro writes the code you would write anyway. You just save the keystrokes.

## Minimal example

Start with a newtype wrapper. A newtype is a tuple struct with a single field. It is the most common use case for `derive_more`.

Here is the smallest case: a wrapper around a string that carries semantic meaning.

```rust
use derive_more::{Deref, From, Display};

/// A wrapper around a String that carries semantic meaning.
#[derive(Debug, Deref, From, Display)]
pub struct UserId(String);

fn main() {
    // From<String> allows this conversion via the From trait.
    let id = UserId::from("user-123");

    // Deref<String> allows calling String methods directly.
    assert_eq!(id.len(), 9);

    // Display formats the inner value.
    println!("ID: {}", id);
}
```

Run this. See the output. The macro did the work.

## How the macro expands

When you write `#[derive(Deref)]` on `UserId(String)`, the macro generates an implementation of the `Deref` trait. The generated code looks like this:

```rust
impl std::ops::Deref for UserId {
    type Target = String;

    fn deref(&self) -> &String {
        &self.0
    }
}
```

For `From`, it generates:

```rust
impl From<String> for UserId {
    fn from(value: String) -> Self {
        UserId(value)
    }
}
```

For `Display`, it generates a `fmt` implementation that writes the inner string. The macro handles the boilerplate of matching the trait signature and delegating to the field. You can verify the expansion by running `cargo expand` in your terminal. This is a valuable debugging tool. If the macro behaves unexpectedly, `cargo expand` shows exactly what code was emitted.

Convention aside: most developers run `cargo expand` once when learning a new macro, then trust it. The macro authors test edge cases extensively. You only need to peek under the hood when the compiler rejects your code and the error message points to macro expansion.

Trust the expansion. If you are curious, run `cargo expand` and read the generated code.

## Realistic usage: wrappers and errors

Real code often involves enums and multiple fields. `derive_more` handles these with attributes. Consider a cache wrapper and an error enum.

Here is a practical setup: a cache that delegates to a `HashMap`, plus an error type that formats itself and converts from `io::Error`.

```rust
use std::collections::HashMap;
use std::io;
use derive_more::{Deref, DerefMut, From, Display, Error};

/// A cache that wraps a HashMap but exposes map-like behavior.
#[derive(Debug, Deref, DerefMut)]
pub struct Cache {
    // Mark the field to dereference.
    #[deref]
    #[deref_mut]
    data: HashMap<String, Vec<u8>>,
}

/// Errors that can occur in the cache.
#[derive(Debug, From, Display, Error)]
pub enum CacheError {
    // From<io::Error> converts io::Error into CacheError::Io.
    #[display(fmt = "IO error: {}", _0)]
    Io(io::Error),
    // From<String> converts String into CacheError::NotFound.
    #[display(fmt = "Key not found: {}", _0)]
    NotFound(String),
}

fn main() {
    let mut cache = Cache { data: HashMap::new() };

    // DerefMut lets us use HashMap methods directly.
    cache.insert("key".to_string(), vec![1, 2, 3]);

    // From allows easy error conversion.
    let err: CacheError = io::Error::other("disk full").into();
    println!("Error: {}", err);
}
```

The `#[deref]` attribute tells the macro which field to target when the struct has multiple fields. Without it, the macro emits an error because it cannot guess. The `#[display(fmt = "...")]` attribute defines the formatting string. `_0` refers to the first field of the variant. For named fields, you can use the field name directly.

Convention aside: always place `#[deref]` and `#[deref_mut]` on the same field unless you deliberately want asymmetric read and write targets. Mixing them across fields confuses readers and breaks the mental model of a transparent wrapper.

Wrap the complexity. Expose the simplicity. That is the newtype pattern.

## Advanced traits: Display, TryFrom, and more

`derive_more` covers more than the basics. The `Display` derive supports rich formatting. You can reference fields by name or position.

Here is a struct that formats itself with custom syntax:

```rust
use derive_more::Display;

#[derive(Display)]
pub struct User {
    #[display(fmt = "User({name}, {age})")]
    name: String,
    age: u8,
}
```

When conversion can fail, use `TryFrom`. The macro generates a `Result` wrapper automatically.

```rust
use derive_more::TryFrom;

#[derive(TryFrom)]
pub struct Positive(i32);
```

This generates `impl TryFrom<i32> for Positive` that returns `Err` for negative values if you add validation logic, or simply wraps the value. For enums, `TryFrom` can convert from a variant's inner type.

Sometimes you just want a constructor function. `#[derive(Constructor)]` adds a `new()` function.

```rust
use derive_more::Constructor;

#[derive(Constructor)]
pub struct Point {
    x: f64,
    y: f64,
}

// Generates: impl Point { pub fn new(x: f64, y: f64) -> Self { ... } }
```

For enums, `#[derive(IsVariant)]` adds boolean check methods.

```rust
use derive_more::IsVariant;

#[derive(IsVariant)]
pub enum Status {
    Active,
    Inactive,
}

// Generates: impl Status { pub fn is_active(&self) -> bool { ... } }
```

These traits reduce the need for manual impl blocks across your codebase.

## Pitfalls and compiler errors

If you forget to enable a feature in `Cargo.toml`, the macro will not exist. You will get `E0433` (failed to resolve: could not find `Deref` in `derive_more`). The fix is always the feature flag. Check your dependencies first.

If you have a struct with multiple fields and do not mark `#[deref]`, the macro emits an error. The message will say something like "Cannot derive Deref for struct with multiple fields without #[deref] attribute." Add the attribute to the target field.

`From` derives can be tricky for structs with multiple fields. `derive_more`'s `From` usually works for newtypes or enums. For a struct with multiple fields, `From` might not derive automatically for the inner types unless you specify which field to convert from. If you need complex conversion logic, write the impl manually.

`Display` formatting syntax can be strict. If you reference a field that does not exist, the macro emits an error. Ensure field names match. For tuple variants, use `_0`, `_1`. For named fields, use the name.

`derive_more` does not handle serialization. Use `serde` for `Serialize` and `Deserialize`. `derive_more` focuses on traits like `Deref`, `From`, `Display`, and `Error`.

Check your features first. Half of `derive_more` issues are missing flags, not broken code.

## When to use derive_more

Use `derive_more` for newtype wrappers where you want the wrapper to act exactly like the inner type. Use `derive_more` for enums where you need `From`, `TryFrom`, or `Display` based on variants. Reach for manual implementations when the conversion or formatting requires logic beyond field delegation. Use `thiserror` for complex error types with source chains and custom attributes; `derive_more` covers the basics but `thiserror` is the ecosystem standard for errors. Pick `serde` for serialization; `derive_more` focuses on traits like `Deref`, `From`, and `Display`, not data interchange.

Automate the pattern. Write the exception.

## Where to go next

- [Understanding derive macros](/en/understanding-derive-macros)
- [Error handling with thiserror](/en/error-handling-with-thiserror)
- [The newtype pattern](/en/the-newtype-pattern)