JSON to Rust Struct (Serde)

Paste JSON to generate idiomatic Rust struct definitions with serde Serialize/Deserialize derives, snake_case field names, and Option<T> handling.

About This Tool

Hand-writing Rust structs to match a third-party API response is one of those tasks that wears down your enthusiasm for static typing. This converter turns any JSON payload into a complete set of #[derive(Serialize, Deserialize)] structs in milliseconds. It picks idiomatic Rust types (String, i32, f64, bool, Vec<T>, Option<T>), emits separate named structs for nested objects, and rewrites JSON keys into proper Rust snake_case while keeping the original spelling in a #[serde(rename = "...")] attribute when needed.

Type inference walks the entire JSON tree. Numbers without a decimal point become i32 (or i64 if the value exceeds the 32-bit range), numbers with a decimal point become f64, and null is wrapped in Option<serde_json::Value> so you can decide later what concrete type to use. JSON arrays become Vec<T> where T is inferred from the first element. Nested objects spawn their own struct whose name is derived from the parent field — for example, shipping_address becomes the ShippingAddress struct.

If you also need the same data shape in another language, our JSON to TypeScript converter emits interface definitions, JSON to C# produces class POCOs with JsonProperty attributes, and the JSON to Go converter writes equivalent Go structs with json tags. All three pair nicely with this Rust output when you work across multiple services.

Every byte of processing happens in your browser. The JSON you paste is parsed with the native JSON.parse(), walked by a small inference function, and emitted as a Rust source string. Nothing is uploaded, logged, or relayed through a server. That makes the converter safe for internal API responses, authentication payloads, configuration files, or anything else you would not want to share with a third party. Toggle the #[derive] line, the pub field visibility, or the Option<T> wrapping at any time — the output regenerates instantly.

How to Use

  1. Paste or type your JSON into the JSON Input panel on the left.
  2. The Rust struct output regenerates automatically in the right panel.
  3. Set the Root struct name to control the top-level identifier (defaults to Root).
  4. Toggle #[derive(...)] to add or remove the standard Debug, Clone, Serialize, Deserialize derives.
  5. Toggle pub fields to control whether each field carries the pub visibility modifier.
  6. Toggle serde(rename) when JSON keys differ from the generated snake_case Rust names — the attribute keeps round-trip compatibility.
  7. Click Copy or press Ctrl+Shift+C to copy the generated code. Use Sample to load a populated example.

Popular JSON to Rust Examples

View all 15 JSON to Rust examples &rarr;

FAQ

Which Rust types does the converter pick for JSON values?

JSON strings become String. Whole numbers become i32 (or i64 when they exceed the i32 range). Numbers with a fractional part become f64. JSON booleans become bool. JSON null is wrapped in Option<serde_json::Value> so you can refine the inner type once you know the schema. Arrays become Vec<T> where T is inferred from the first element, and nested objects spawn their own named struct.

How are JSON keys converted to Rust field names?

All keys are normalized to snake_case to match Rust style. Original casing is preserved in a #[serde(rename = "originalKey")] attribute when the two differ, so serialization and deserialization remain compatible with the source JSON. Reserved Rust keywords like type or match are escaped as r#type / r#match plus a serde rename to keep the JSON key intact.

How is null handled?

Because JSON null carries no type information on its own, the converter emits Option<serde_json::Value> by default. You can rename the inner type after pasting your JSON — for example, change Option<serde_json::Value> to Option<String> if you know the field is a nullable string. If you turn off the Option<T> toggle, null becomes a plain serde_json::Value instead.

Why does my array of objects only generate one struct?

Element type inference uses the first element of each array as the canonical sample. If your array has heterogeneous shapes, edit the sample JSON to use the most complete element first, or post-process the generated struct to add Option<T> on fields that may be missing. This mirrors how serde_json works at runtime — it expects a fixed shape per Vec entry.

Do I need any external crates besides serde?

Yes — add serde with the derive feature and serde_json to your Cargo.toml. A typical configuration is serde = { version = "1", features = ["derive"] } and serde_json = "1". The serde_json crate is needed because Option<serde_json::Value> is used for unknown null types in the generated output.

Is my data safe?

Yes. Your JSON is parsed with the browser's native JSON.parse() and the Rust source code is built with simple JavaScript string concatenation. There are no network requests, no third-party libraries fetching your input, and no analytics on the JSON itself. You can verify this by opening DevTools and watching the Network tab while you paste — there are no outbound requests.

Can I generate Rust enums for string union fields?

Not automatically — the converter cannot infer that the same string field always takes one of a fixed set of values from a single sample. The recommended workflow is to generate the struct with the field as String, then manually replace it with a #[derive(Serialize, Deserialize)] pub enum. The Examples gallery has a worked walkthrough of this pattern.

Related Tools