Rust Newtype Pattern for Stronger Domain Types

Wrap a primitive in a one-field tuple struct so the type system can distinguish UserId from OrderId. Free strong typing with zero runtime cost.

Patterns

Detailed Explanation

The Newtype Pattern with serde

A newtype is a tuple struct with exactly one field. It looks pointless at first — UserId is just an i64 underneath — but it lets the compiler reject calls like assign_to(order_id) when the function expects a UserId.

Starting JSON

{
  "user_id": 1234567,
  "order_id": 9876543
}

Auto-generated output

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Root {
    pub user_id: i32,
    pub order_id: i32,
}

Promoted to newtypes

#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct UserId(pub i64);

#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct OrderId(pub i64);

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Root {
    pub user_id: UserId,
    pub order_id: OrderId,
}

Transparent serialization

By default, serde serializes a tuple struct as a single-element array: UserId(1) becomes [1]. To make it serialize as the inner value (1), add #[serde(transparent)]:

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[serde(transparent)]
pub struct UserId(pub i64);

Now the round-trip JSON looks identical to a bare i64, and Rust still rejects accidental mixing.

Adding domain methods

Newtypes can have methods, traits, and constructors:

impl UserId {
    pub fn new(id: i64) -> Result<Self, &'static str> {
        if id <= 0 { return Err("id must be positive"); }
        Ok(UserId(id))
    }
}

This pattern is the foundation of "parse, don't validate" — once you have a UserId, you know it is valid and you cannot accidentally construct a bad one.

Use Case

Domain-driven design, financial calculations, and any codebase with multiple ID types benefit from newtypes. They prevent the entire class of 'wrong ID passed to wrong function' bugs at compile time.

Try It — JSON to Rust Struct Converter

Open full tool