UtilityKit

500+ fast, free tools. Most run in your browser only; Image & PDF tools upload files to the backend when you run them.

JSON to Rust Struct

Generate Rust structs from JSON with serde rename hints.

About JSON to Rust Struct

Rust's ownership model and strict type system make it excellent at handling JSON safely, but writing the boilerplate for serde deserialization by hand is one of the more repetitive tasks in Rust development. Every field needs its type, every struct needs #[derive(Serialize, Deserialize)], and snake_case Rust conventions often conflict with the camelCase or snake_case keys in the incoming JSON. JSON to Rust Struct eliminates that friction: paste any JSON object or array and receive complete Rust struct definitions with #[derive(Debug, Clone, Serialize, Deserialize)], serde rename attributes where the field name differs from the JSON key, and correct type mappings — String, i64, f64, bool, Option<T> for nullable fields, Vec<T> for arrays, and nested struct types for nested objects.

Why use JSON to Rust Struct

Eliminates Serde Boilerplate

Generating derive macros, rename attributes, and nested struct definitions for a 30-field API response by hand can take 20 minutes — the converter does it in under a second.

Correct Option<T> for Nullable Fields

JSON null maps to Option<T> so your code handles missing fields correctly without runtime panics or misuse of Default::default().

Serde Rename Attributes Included

camelCase or PascalCase JSON keys that cannot map directly to snake_case Rust fields get a #[serde(rename = "...")] attribute automatically, preventing silent deserialization failures.

Full Derive Macro Stack

Each struct gets #[derive(Debug, Clone, Serialize, Deserialize)] covering the most common traits needed for logging, cloning, and round-trip JSON handling.

Works Without Rust Installed

Run the converter in any browser — useful during architecture planning, API contract reviews, or on machines that do not have a Rust toolchain installed.

No Data Leaves the Browser

The conversion runs entirely client-side. API response samples that may contain sensitive fields or proprietary data structures are never transmitted to any server.

How to use JSON to Rust Struct

  1. Paste your JSON object or array into the input panel — use a real, fully-populated API response for the most accurate type mapping.
  2. The tool inspects every key and value, mapping JSON types to Rust types: strings to String, integers to i64, decimals to f64, booleans to bool, and null to Option<T>.
  3. Field names are emitted in snake_case; when the original JSON key differs (e.g. camelCase userId), a #[serde(rename = "userId")] attribute is added to the field.
  4. Nested objects generate separate named Rust structs, referenced by value in the parent struct (not as references or pointers, matching serde conventions).
  5. Arrays of objects produce Vec<StructName> types; arrays of primitives produce Vec<String>, Vec<i64>, Vec<f64>, etc.
  6. Copy the generated code, add it to your Rust source file, and use serde_json::from_str(&json_string) or serde_json::from_value(json_value) to deserialize your data.

When to use JSON to Rust Struct

  • When building a Rust web service with Axum or Actix-Web that receives or returns JSON and you need serde structs for the request and response bodies.
  • When writing a Rust CLI tool that fetches data from a REST API and you want strongly-typed deserialization instead of working with serde_json::Value.
  • When onboarding a new API integration in an existing Rust project and you have a real JSON response to work from but no official Rust types provided.
  • When porting a Go, Python, or TypeScript service to Rust and you need to replicate the JSON data model as serde-compatible Rust structs.
  • When prototyping a new feature where you want to start with typed structs before writing business logic, using a fixture JSON response as the type source.
  • When auditing an undocumented internal API by capturing a real response payload and immediately generating usable Rust types from it.

Examples

Simple user object

Input: { "userId": 1, "displayName": "rustacean", "active": true, "score": 98.6 }

Output: #[derive(Debug, Clone, Serialize, Deserialize)] pub struct AutoGenerated { #[serde(rename = "userId")] pub user_id: i64, #[serde(rename = "displayName")] pub display_name: String, pub active: bool, pub score: f64, }

Nested object with nullable field

Input: { "name": "Alice", "address": { "street": "123 Main St", "unit": null } }

Output: #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Address { pub street: String, pub unit: Option<String>, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct AutoGenerated { pub name: String, pub address: Address, }

Array of tagged items

Input: [{"id":1,"tag":"featured","views":1024},{"id":2,"tag":"new","views":512}]

Output: #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Item { pub id: i64, pub tag: String, pub views: i64, } // Deserialize as: let items: Vec<Item> = serde_json::from_str(json)?;

Tips

  • Add #[serde(rename_all = "camelCase")] at the struct level when the JSON uses consistent camelCase keys — this removes the need for per-field rename attributes and keeps the generated code much shorter.
  • For date-time string fields like '2026-05-07T12:00:00Z', change the generated String type to chrono::DateTime<Utc> (with the chrono serde feature enabled) to get automatic parsing and type safety.
  • Use #[serde(skip_serializing_if = "Option::is_none")] on Option fields to prevent null keys from appearing in serialized JSON output when the value is absent.
  • Prefix generated inner struct names with the parent context (e.g. UserAddress instead of Address) to avoid name conflicts when multiple top-level structs have fields with the same key name.
  • Run cargo fmt on the generated code after pasting — serde derive attributes and struct field alignment benefit from rustfmt's automatic formatting to match community style.

Frequently Asked Questions

What serde version does the generated code target?
The output is compatible with serde 1.x and serde_json 1.x, which are the stable current versions. Add serde = { version = "1", features = ["derive"] } and serde_json = "1" to your Cargo.toml to use the generated structs.
How are JSON numbers mapped to Rust types?
Whole numbers (e.g. 42) map to i64 to handle the full range of JSON integer values. Decimal numbers (e.g. 3.14) map to f64. If you know a field will always be a small non-negative integer, you can manually change i64 to u32 or usize after generation.
How are null and missing JSON fields handled?
null values in the JSON sample map to Option<T> — for example, a null string becomes Option<String>. You can also add #[serde(skip_serializing_if = "Option::is_none")] to omit the field from serialized output when the value is None.
What happens with camelCase JSON keys?
camelCase keys like userId or createdAt are emitted as snake_case field names (user_id, created_at) and annotated with #[serde(rename = "userId")] to preserve correct deserialization. Alternatively, you can add #[serde(rename_all = "camelCase")] at the struct level and remove per-field renames.
Does the output include Serialize or just Deserialize?
Both — the derive macro is #[derive(Debug, Clone, Serialize, Deserialize)] so the structs support both serde_json::to_string() serialization and serde_json::from_str() deserialization out of the box.
How are nested JSON objects handled?
Each nested object produces a separate named Rust struct. The parent struct holds the nested struct by value (not a reference), which is the idiomatic serde pattern for owned deserialized data.
What type is used for JSON arrays?
Arrays produce Vec<T> where T is inferred from the array elements. An array of strings becomes Vec<String>, an array of objects becomes Vec<StructName>, and a mixed-type array becomes Vec<serde_json::Value>.
Can I use the generated structs with Axum or Actix-Web extractors?
Yes. Axum's Json<T> extractor and Actix-Web's web::Json<T> both use serde_json internally. Any struct with #[derive(Deserialize)] can be used directly as an extractor type without additional configuration.

Explore the category

Glossary

serde
A Rust framework for serializing and deserializing data structures. The #[derive(Serialize, Deserialize)] macros from serde generate code to convert Rust structs to and from formats like JSON, TOML, and MessagePack.
serde_json
The serde data format implementation for JSON. Provides serde_json::from_str(), serde_json::to_string(), and serde_json::Value for working with JSON data in Rust.
Option<T>
Rust's nullable type — Option::Some(T) holds a value and Option::None represents absence. Used to represent JSON null values and optional fields in serde structs.
#[serde(rename)]
A serde field attribute that maps a Rust struct field name to a different JSON key. Used when the JSON key does not match the snake_case Rust field name.
#[serde(rename_all)]
A serde struct-level attribute that applies a naming convention to all fields at once. Common values: "camelCase", "PascalCase", "snake_case". Avoids per-field rename attributes for consistently-cased JSON.
Derive Macro
A Rust procedural macro invoked with #[derive(...)] that auto-generates trait implementations for a struct. serde's derive macros generate the Serialize and Deserialize implementations at compile time.