Formatter Validator Minifier Escape / Unescape JSON ↔ String JSON ↔ YAML JSON → CSV NDJSON / JSON Lines JSON → Types JSON ↔ XML JSON Diff JSON Patch Canonicalize (RFC 8785) Schema Validator Schema Generator JSONPath Tester JWT Decoder JSON Errors Schemas More Tools
● RUST SERDE STRUCTS · 100% BROWSER-BASED

JSON to Rust

Paste a JSON sample and get Rust serde structs, instantly and entirely in your browser. Optional fields, nullability and nested types are inferred from the sample — and anything the sample cannot settle is reported rather than guessed.

JSON sample
TypeScript interface
Type definitions will appear here

Rust serde structs from a sample

Generates #[derive(Serialize, Deserialize)] structs, with #[serde(rename)] when the Rust name differs from the JSON key.

Optional fields get Option<T> plus skip_serializing_if.

What a sample cannot tell you

Types are inferred from one sample. A field absent from your sample will be absent from the output, and a field that happens to hold only whole numbers will be typed as an integer even if it can hold decimals. Paste the widest sample you have. For a guarantee rather than an inference, start from a JSON Schema.

What Rust output looks like

Generated from two sample records, one of which has an extra field and a null. This is the actual output, not an illustration:

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Root {
    pub id: i64,
    #[serde(rename = "userName")]
    pub user_name: String,
    #[serde(rename = "isActive")]
    pub is_active: bool,
    pub score: f64,
    pub tags: Vec<String>,
    pub address: Address,
    #[serde(rename = "lastSeen")]
    pub last_seen: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub nickname: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Address {
    pub city: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub postcode: Option<serde_json::Value>,
}

The three things that differ by language

Large integers

Rust has i64, so large identifiers survive. serde will refuse a value that does not fit rather than truncating it, which is the behaviour you want.

Optional against nullable

Optional fields become Option<T> with #[serde(skip_serializing_if = "Option::is_none")], so a None is omitted rather than written as null.

Names that are not identifiers

#[serde(rename)] is emitted where the Rust name differs from the key, keeping snake_case idiomatic without breaking the wire format.

Convert the same JSON to