JSON to Rust Structs (serde)

Generate Rust structs with serde Serialize/Deserialize derives, snake_case fields, rename attributes, Option for nulls and Vec for arrays from JSON. Free.

Requires the serde (with derive) and serde_json crates. Fields are snake_case with #[serde(rename)] where the JSON key differs.

Runs entirely in your browser. Your data is never uploaded.

Related Tools

View All

What is JSON to Rust?

Paste JSON and get Rust struct definitions that deserialize it with serde. Every struct derives Debug, Clone, Serialize, Deserialize; field names are snake_case and keep the original key with #[serde(rename = "…")] where needed.

How to use JSON to Rust

  1. Paste a JSON sample into JSON input (or click Load sample / Open file).
  2. Set the Root type name (default Root).
  3. Copy the generated Rust code or Download it as a file.

Example

Input
{"id":1,"name":"A","tags":["x"]}
Output
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Root {
    pub id: i64,
    pub name: String,
    pub tags: Vec<String>,
}

When to use JSON to Rust

Use it when writing a Rust client or CLI that reads JSON. Refine the types afterwards – for example u32 for small counts or chrono types for timestamps – because a sample cannot tell you the real ranges.

How JSON to Rust works

The sample is walked recursively and every position collects the types it has seen. Arrays of objects are merged into one type: a key missing from some elements becomes optional, a key that is null somewhere becomes nullable, integers mixed with decimals become a floating-point type, and anything else that mixes types falls back to a dynamic type. Nested objects become their own named types (PascalCase of the key, array keys singularized: orders → Order), with numeric suffixes when names collide. Rust output maps integers to i64, decimals to f64, strings to String, booleans to bool, arrays to Vec<T>, nullable values to Option<T> and dynamic or null-only values to serde_json::Value. Fields missing from some samples become Option<T> with #[serde(default, skip_serializing_if = "Option::is_none")]. Keywords such as type are written as raw identifiers (r#type).

Common Use Cases

  • Deserialize a REST API response with reqwest + serde
  • Model a JSON config file for a CLI tool
  • Create types for a webhook handler
  • Convert fixtures for Rust integration tests

FAQs

Which crates do I need?

serde with the derive feature and serde_json: serde = { version = "1", features = ["derive"] } and serde_json = "1".

Why serde_json::Value?

It is used when a key mixes types or is always null in the sample, so no concrete Rust type can be chosen safely.

Why r#type?

type is a Rust keyword; the raw identifier syntax lets you use it as a field name while serde still matches the JSON key.

Explore more categories