Paste a JSON object or API response and get idiomatic Rust structs that compile with serde: snake_case fields, #[serde(rename_all)] or per-field renames, Option<T> for nullable values, Vec<T> for arrays and a struct for every nested object. Everything runs in your browser.
Last updated:
Your JSON is parsed locally in this tab and never uploaded. Tip: Ctrl + Enter generates.
Advertisement
Advertisement
How to use the JSON to Rust Struct
Paste your JSON into the left box or open a .json file. A sample is loaded so you can see the output right away.
Name the root struct, for example User or ApiResponse.
Pick the options: which serde derives to add, the integer type, rename_all or per-field renames, Option for missing fields and extra derives.
Press Generate Rust Structs. With Live update on, the code refreshes as you type.
Copy or download the .rs file, add serde (with the derive feature) and serde_json to Cargo.toml, and call serde_json::from_str.
Example: JSON to Rust structs with serde
This response has camelCase keys, a nullable value, a Rust keyword as a key and an array of objects where one key is optional:
score is f64 because one item has 4.5, cover_image is an Option because only one post has it, and avatar_url is Value because it is only ever null, so its type is unknown. Change it to Option<String> once you know.
How JSON values map to Rust types
JSON value
Rust type
"text"
String
42
i64 (or i32 / u64 by option)
3.14, 1e6
f64
true / false
bool
"x" or null
Option<String>
Key missing in some items
Option<T> (or #[serde(default)])
{ … }
A named struct
{}
HashMap<String, Value>
[1, 2] / []
Vec<i64> / Vec<Value>
null only, or mixed types
serde_json::Value
Using the structs
# Cargo.toml
[dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = "1"
// main.rs
let root: Root = serde_json::from_str(&json)?;
println!("{}", root.posts[0].r#type);
let back = serde_json::to_string_pretty(&root)?;
Unknown keys are ignored by default. Turn on deny_unknown_fields to make deserialization fail when the JSON has keys the struct does not know.
skip_serializing_if leaves None fields out of the output instead of writing null, which keeps serialized JSON closer to the original.
Dates stay String. For typed timestamps add the chrono crate with its serde feature and change the field to chrono::DateTime<chrono::Utc>.
Frequently asked questions
Which crates do the generated structs need?
Add serde with the derive feature and serde_json to Cargo.toml: serde = { version = "1", features = ["derive"] } and serde_json = "1". The structs use #[derive(Serialize, Deserialize)] from serde and, when a field can hold mixed types, serde_json::Value.
How are JSON keys turned into Rust field names?
Each key is split into words at camelCase boundaries, dashes, spaces and underscores, then joined in snake_case, so userName becomes user_name. If most keys in a struct follow one convention, the generator adds #[serde(rename_all = "camelCase")] (or PascalCase, kebab-case or SCREAMING_SNAKE_CASE) and only adds #[serde(rename = "...")] to keys that do not fit, so serde still reads the original JSON.
When does a field become Option<T>?
A field becomes Option<T> when it is null in at least one place, or (with the option on) when the key is missing from some items of an array. serde deserializes a missing Option field as None automatically. If you turn the option off, missing fields get #[serde(default)] instead.
What happens to Rust keywords like type or match?
Keywords are written as raw identifiers, for example pub r#type: String. serde strips the r# prefix, so the field still maps to the JSON key "type". self, Self, super and crate cannot be raw identifiers, so they get a trailing underscore plus a rename attribute.
How are numbers typed?
Whole numbers become i64 by default, and numbers with a decimal point or exponent become f64. You can choose i32 when every value fits in 32 bits, or u64 when no value is negative. If a field mixes whole and decimal numbers it becomes f64. Integers too large for 64 bits are treated as f64.
What about null-only fields, empty arrays and mixed types?
If a value is always null, its real type cannot be known, so it becomes serde_json::Value. Empty arrays become Vec<Value> and fields that mix types (such as a string in one item and a number in another) also use Value, because Rust has no ad-hoc union types. Replace them with a concrete type or an enum once you know the data.
Is my JSON uploaded anywhere?
No. Parsing and code generation are plain JavaScript running in this page, so API responses containing personal or secret data never leave your device.
Are all the tools on FreeToolCabin tested for quality and accuracy?
Yes! Every tool on our site undergoes automated Q/A testing in real browser environments to ensure high precision, correct output, and zero errors. If you happen to spot a bug or have a suggestion, please contact us at [email protected] and our team will review it right away.