# Implement custom Debug in Rust

> Implement Rust's Debug trait manually with Formatter::debug_struct, choose which fields appear, redact sensitive values, and keep {:#?} pretty printing.

HTML: https://rustprint.com/debug/implement-debug/

Implement `std::fmt::Debug` manually when `#[derive(Debug)]` exposes the wrong representation. The usual struct-shaped implementation uses `Formatter::debug_struct()`, adds only the fields you want, and finishes the builder.

**Implement Debug manually and redact a field**

```rust
struct Account {
    username: &'static str,
    api_key: &'static str,
}

impl fmt::Debug for Account {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        formatter
            .debug_struct("Account")
            .field("username", &self.username)
            .field("api_key", &"[redacted]")
            .finish()
    }
}
```

RustPrint runs this implementation in CI. The test verifies that the visible field is present, the placeholder is present, and the original secret value is absent from the formatted output.

## The Debug trait method

A manual implementation provides one method:

```rust
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
```

The formatter is the destination and carries formatting options such as the alternate `#` flag used by `{:#?}`.

For most structs, use the formatter's debug builder rather than manually assembling punctuation. `debug_struct()` produces the normal struct-shaped Debug representation and supports pretty Debug automatically.

## Choose which fields appear

Unlike `#[derive(Debug)]`, a manual implementation does not have to include every field. You decide which calls to `.field()` are made and what value each field shows.

That is useful when a type contains internal state that is noisy, expensive to inspect, irrelevant to diagnostics, or sensitive. In the checked example, the real API key is deliberately replaced with a constant placeholder.

A custom Debug implementation should not be treated as a security boundary by itself. If a value must never be exposed, also control where it can be logged, copied, serialized, or otherwise inspected.

## debug_struct is not the only builder

Rust's `Formatter` also provides builders for common Debug shapes:

- `debug_tuple()` for tuple-like output
- `debug_list()` for sequence-like output
- `debug_set()` for set-like output
- `debug_map()` for key-value output

These helpers let a manual implementation keep the conventional Rust Debug style instead of recreating brackets and separators yourself.

## You can write a completely custom representation

If none of the builders match the representation you want, the `Debug` documentation also permits writing directly to the formatter with `write!`.

That gives you full control, but it also makes you responsible for the entire representation. Prefer the debug builders when the value is still conceptually a struct, tuple, list, set, or map.

## Pretty Debug still works

Manual implementations built with the formatter's debug builders support `{:#?}`. You therefore do not need separate compact and pretty implementations.

The same stability warning still applies: Debug output is programmer-facing inspection text, not a serialization format or wire protocol. See [pretty Debug](/debug/pretty-debug/index.md) for that boundary.

## Derive Debug unless you need control

The standard library recommends deriving `Debug` in the ordinary case. Manual `Debug` is most useful when the derived representation is unavailable or deliberately wrong for diagnostics.

If your problem is simply that the compiler says a type does not implement `Debug`, start with [E0277: type doesn't implement Debug](/errors/doesnt-implement-debug/index.md). If you only want to inspect an ordinary struct, [print structs and arrays](/debug/print-struct/index.md) is the shorter path.

## Sources

- [std::fmt::Debug](https://doc.rust-lang.org/std/fmt/trait.Debug.html)
- [std::fmt::DebugStruct](https://doc.rust-lang.org/std/fmt/struct.DebugStruct.html)

## Related RustPrint guides

- [Print structs and arrays in Rust](/debug/print-struct/index.md): Print a Rust struct by deriving Debug and using {:?} or {:#?}, and print arrays with the same Debug formatting syntax.
- [Rust pretty print a struct with {:#?}](/debug/pretty-debug/index.md): Pretty print Rust structs, enums, maps, and nested values with {:#?}, derive Debug, and understand why Debug output is not a stable serialization format.
- [Debug vs Display in Rust](/debug/debug-vs-display/index.md): Choose between Rust Debug and Display based on programmer-facing inspection versus deliberate user-facing text.
- [Rust E0277: type doesn't implement Debug](/errors/doesnt-implement-debug/index.md): Fix Rust E0277 when a value cannot be formatted with {:?} because its type does not implement std::fmt::Debug.
