CalcCafe

YAML to Rust

Paste YAML and instantly get Rust struct definitions with inferred field types, ready for serde.

Example

Input YAML:

name: Alice
age: 30
tags:
 - admin
 - user

Output Rust:

use serde::{Serialize, Deserialize};

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

How it works

It parses your YAML with js-yaml, walks the resulting value to infer a type model (objects become structs, arrays become Vec, missing keys become Option), then emits idiomatic Rust with the root type named Root.

Good to know

YAML to Rust turns a block of YAML into ready-to-compile Rust type definitions, generating structs with #[derive(Debug, Clone, Serialize, Deserialize)] so the output drops straight into a serde-based project. It is built for Rust developers who need to deserialize a config file, an API response, or a Kubernetes/CI manifest and want the boilerplate type scaffolding written for them instead of by hand.

Reach for it whenever you have a concrete YAML sample and need matching Rust types: wiring up serde_yaml for application config, modeling a third-party schema you only have examples of, or quickly prototyping data structures before refining them. Because everything runs in your browser via js-yaml, you can paste private or internal YAML without it leaving your machine.

Read the output top-down: the entry type is always named Root, and nested mappings become their own structs referenced by field. Field types are inferred from the values you provide, so the result is only as accurate as your sample. Watch for these inference rules:

One practical caveat: list element types are inferred from the first item, and if elements disagree the field falls back to serde_json::Value. Feed it a representative sample that includes every optional key (anything that can be null becomes Option), then review numeric widths and any serde_json::Value fallbacks before committing the generated code.

Frequently asked questions

How are nested objects and arrays mapped to Rust?
Each nested mapping becomes its own struct named after its key (in PascalCase), and sequences become Vecwhere T is inferred from the first element. Arrays of objects generate a singular-named struct for the element type.
What happens with null values or empty lists?
A null value produces Optionand an empty list produces Vec, since the concrete type cannot be inferred. Keys whose value is null are also wrapped in Option.
Is my data uploaded anywhere?
No — this tool runs entirely in your browser. Your input never leaves your device and it works offline once loaded.
Is it free?
Yes, completely free with no sign-up and no limits.

People also ask

Does YAML to Rust generate serde derive attributes automatically?
Yes. Every generated struct carries #[derive(Debug, Clone, Serialize, Deserialize)], and any key that isn't a valid Rust identifier also gets a #[serde(rename = "...")] attribute so the original YAML key is preserved during serialization.
How does the tool decide between i64 and f64 for numbers?
It inspects the actual value: a finite number with no fractional part is treated as i64, while a number with a decimal component becomes f64. To force a float field, include a decimal point in the sample value.
What crate do I need to actually deserialize the generated structs?
The structs use serde, so you need the serde crate with the derive feature, plus a format crate such as serde_yaml (or serde_json) to parse the data into the types. The output also references serde_json::Value as a fallback for untyped values.
Why did a field come out as serde_json::Value instead of a concrete type?
That fallback appears when a type cannot be inferred: an empty list, a null value, or a list whose elements have inconsistent types. Provide a fuller sample with non-empty, uniform values to get a more specific type.
Can it handle a YAML file whose top level is a list instead of a key-value mapping?
Yes. When the root is not a mapping, the tool wraps it in a Root struct with a single 'value' field whose type reflects the top-level content, such as a Vec for a list.
How are duplicate or repeated struct names handled?
Generated struct names are de-duplicated by appending a number, so two nested objects that would otherwise share a name produce distinct types like Item and Item2 rather than colliding.
Will the generated Rust compile as-is?
It is designed to be idiomatic and compile-ready once you add the serde and serde_json dependencies, but you should review inferred numeric widths, optional fields, and any serde_json::Value fallbacks, since those reflect what could not be determined from a single sample.

Related tools