Skip to content

JSON to Rust Struct Converter

Paste JSON, get idiomatic Rust serde structs instantly, 100% in your browser. Correct i64/u64/f64 typing, Option for nulls, #[serde(rename)] for camelCase. Free.

No Tracking Runs in Browser Free
Options
0 chars
Rust Output
0 lines
Output verified against serde semantics and rustfmt formatting for real-world API payloads. — Go Tools Team · Jul 2, 2026

What is JSON to Rust conversion?

JSON to Rust conversion turns a JSON sample into ready-to-compile Rust structs with serde's #[derive(Serialize, Deserialize)] macros, so you never hand-write deserialization boilerplate for API responses or config files. This fast Rust struct generator infers correct number types, marks absent fields as Option, and adds #[serde(rename)] for non-snake_case keys — all 100% in your browser.

Examples

API response

{"id":101,"name":"Ada Lovelace","email":"ada@example.com","active":true,"roles":["admin","user"]}
use serde::{Deserialize, Serialize};

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

A typical REST payload becomes a serde-ready struct you can drop into your client. Numbers infer i64, arrays become Vec<String>.

Nested object

{"repo":"serde","owner":{"login":"dtolnay","id":100}}
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Root {
    pub repo: String,
    pub owner: Owner,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Owner {
    pub login: String,
    pub id: i64,
}

Nested objects become separate, named structs (Owner) referenced by field — identical shapes are deduplicated.

Array of objects (optional field)

{"users":[{"id":1,"nick":"x"},{"id":2}]}
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Root {
    pub users: Vec<User>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct User {
    pub id: i64,
    pub nick: Option<String>,
}

Arrays of objects merge into one element struct. Keys missing from some items become Option<String> — no #[serde(default)] needed.

camelCase keys

{"login":"octocat","publicRepos":15,"followerCount":9001,"createdAt":"2011-01-25"}
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Root {
    pub login: String,
    #[serde(rename = "publicRepos")]
    pub public_repos: i64,
    #[serde(rename = "followerCount")]
    pub follower_count: i64,
    #[serde(rename = "createdAt")]
    pub created_at: String,
}

Fields become snake_case with #[serde(rename)] mapping back to the original JSON key. Already-snake keys like login get no rename.

How to convert JSON to Rust

  1. 1

    Paste your JSON

    Drop a JSON object, array, or API response into the input box. Conversion starts instantly.

  2. 2

    Tune the output

    Rename the root struct and toggle serde derives, Debug and Clone, or pub visibility to match your crate's style.

  3. 3

    Copy or download

    Grab the generated Rust with one click and paste it straight into your project.

Common Use Cases

Typed API clients
Turn a sample REST or GraphQL response into serde structs for a reqwest or similar client without writing deserialization boilerplate by hand.
Config and fixture parsing
Generate structs for JSON config files, test fixtures, or webhook payloads you need to deserialize with serde_json.
Fast prototyping
Paste an unfamiliar payload to instantly see its shape as Rust types — a quick way to explore a new API before wiring it up.

How the conversion works

Structural inference
Each object becomes a named struct; identical shapes are deduplicated so you get one struct, not copies. Arrays of objects are merged key-by-key, and keys absent from some items become Option<T>.
Correct number typing
Integers map to i64, promote to u64 past i64::MAX, and fall back to f64 beyond u64. Floats are detected from the token (1.0, 2e3) so serde deserialization never fails on a float-into-integer mismatch.
Idiomatic, compilable identifiers
Keys become snake_case fields with #[serde(rename)] back to the original key; Rust keywords, duplicate names, and non-identifier keys are sanitized so the output always compiles.
100% client-side
Parsing and generation run in your browser with no network calls, so your data stays private.

Tips for clean Rust structs

Name your root struct
Set a meaningful root name (e.g. User, ApiResponse) instead of the default Root for readable code.
Add serde_json only when needed
serde_json::Value appears for empty or mixed-type arrays and null-only fields. Give those fields a concrete type from a richer sample if you can, or add serde_json to Cargo.toml.
Review Option vs required
Fields are marked Option<T> only when a sample omits them. Paste a representative payload so the tool infers required and optional fields accurately.

Frequently asked questions

How do I convert JSON to a Rust struct?
Paste your JSON into the input box. The converter parses it instantly in your browser and generates Rust structs with serde derives on the right. Click Copy to grab the result — no upload, no account, no waiting.
Does it generate serde derives? Do I need serde and serde_json?
Yes — output uses #[derive(Debug, Clone, Serialize, Deserialize)] by default. Add serde with the derive feature to your Cargo.toml. You only need serde_json as a dependency if the output contains serde_json::Value, which appears for empty or mixed arrays and null-only fields. Turn off the serde toggle to emit plain structs.
How do I use the generated struct to parse JSON?
Add serde_json to your Cargo.toml, then deserialize in one line: let root: Root = serde_json::from_str(json)?;. The generated Deserialize derive does the rest — use serde_json::from_slice for a byte slice or from_reader for a file or HTTP body, and serde_json::to_string to serialize back.
How are optional and null fields handled?
When a key appears in some array items but not others, it becomes an Option field. A field that is only ever null becomes an optional serde_json::Value. serde treats Option as optional automatically, so no #[serde(default)] attribute is added or required.
How does it handle camelCase keys and Rust keywords?
Field names are converted to idiomatic snake_case, and a #[serde(rename)] attribute maps them back to the exact JSON key. Reserved keywords like type or match are emitted as type_ or match_ with a rename, which is more robust than raw identifiers because it also covers self, crate, and super.
Can it use #[serde(rename_all)] instead of per-field renames?
The tool emits a per-field #[serde(rename)] because it always works — even when one payload mixes camelCase, snake_case, and irregular keys. If every field in a struct shares one convention, delete those attributes and put a single #[serde(rename_all = "camelCase")] on the struct instead; both deserialize identically.
What Rust number type does it use?
Integers map to i64, or u64 when a value exceeds i64::MAX, and fall back to f64 beyond u64 — so large IDs still round-trip. Any number written with a decimal point or exponent (like 1.0 or 2e3) maps to f64, because serde would reject a float into an integer field.
How are dates and timestamps typed?
JSON has no date type, so ISO strings like 2011-01-25 or RFC 3339 timestamps come out as String. For real date handling, change the field to a chrono type — DateTime in the Utc time zone, or NaiveDate — and enable chrono's serde feature. serde then parses RFC 3339 automatically.
How do I handle objects with dynamic or unknown keys?
When keys vary — for example a map of IDs to values — replace the generated struct with a HashMap keyed by String. To keep a typed struct but still capture extra fields, add a #[serde(flatten)] field that is a HashMap. For fully dynamic values, serde_json::Value is the catch-all type.
Is my JSON data private and safe?
Yes. Conversion runs 100% in your browser with JavaScript. Your JSON — including tokens, IDs, or customer data — never leaves the page and is never sent to a server.
Can I generate plain Rust structs without serde?
Yes. Turn off the serde toggle to drop the use serde line, the Serialize and Deserialize derives, and all #[serde(rename)] attributes — leaving clean structs. You can also toggle Debug and Clone derives and pub visibility.
Is the tool free? Do I need an account?
It is completely free with no sign-up, no limits, and no ads cluttering the workspace.

Related Tools

View all tools →