A schema from one sample is a list of guesses. Read them.
JSON Schema describes every document a field will ever hold. A YAML file shows you one. Going from the second to the first means deciding, for each key, whether the value in front of you is the only shape allowed or one of several. No generator knows the answer. What a good one does is make a defensible default and say out loud where the default was applied, so you spend your review time on the twelve lines where the guess was wrong instead of rereading the two hundred where the guess was fine. That is the reason the panel under the output exists. Each row is one decision the generator took on your behalf. Amber rows are the ones a validator will punish you for later.
The required trap
Every key in a sample is present, by definition. A generator with no other information has three honest choices: mark all of them required, mark none, or mark the ones with a non-null value. The first option is the strictest and is the default here, because a schema that is too strict fails loudly on the first document that omits a key, and a schema that is too loose fails silently forever. Switch to Keys with a value when your sample uses ~ or an empty value to mean "optional, not set today". Switch to None when the file is a partial override, such as a Helm values file, where nearly every key is optional by design.
service: api.toolexe.com
replicas: 3
canary: ~
region: eu-west-1Every key present ["service","replicas","canary","region"]Keys with a value ["service","replicas","region"]None (key omitted)When the sample is a list of objects, the generator has more to go on. It reads every item, not the first one, and a key becomes required only when every item carries it. A key that shows up in two of three items is left out of required and gets an info row naming the count, so you know the omission was evidence, not a default.
30, "30", 3.0 and 0755
YAML resolves scalar types before any converter runs. This page reads YAML through js-yaml 4, which follows the YAML 1.2 core schema, and the schema you get reflects what the parser handed over, not what you typed.
replicas: 30arrives as a number with no fraction and becomes"type": "integer".replicas: "30"arrives as a string and stays a string. Remove the quotes if the field is numeric.ratio: 3.0arrives as the number 3. JavaScript has no separate float, so the fraction is gone before the generator looks. The page scans the raw text for values written with a.0tail and emitsnumberfor those keys, with an info row explaining why.mode: 0755arrives as 755. YAML 1.2 dropped the leading-zero octal form, and js-yaml discards the zero rather than treating the value as base 8. Write0o755for octal, or quote it if the string form is what your application reads.debug: yesstays the string"yes". Onlytrueandfalseresolve to booleans under YAML 1.2. A YAML 1.1 parser, which PyYAML still is, would read the same line as a boolean, and the page flagsyes,no,onandoffso you pick one spelling before the schema and the other parser disagree.timeout: .infand.nanresolve to values JSON cannot carry. The type isnumber, and the example, if you enabled examples, is written asnull, which is whatJSON.stringifydoes with an infinity.
Dates that were parsed before you asked
An unquoted 2024-03-08 or 2024-03-08T09:30:00Z matches the YAML timestamp tag, and js-yaml turns it into a JavaScript Date object. The generator never sees the original text. It writes "type": "string" and picks "format": "date" when the parsed value sits at midnight UTC, "format": "date-time" otherwise. That midnight rule is a heuristic. A value written as 2024-03-08T00:00:00Z comes out as date even though the source carried a time. If the distinction matters, quote the value in the YAML so it stays a string, and format detection reads the actual characters.
With formats enabled, quoted strings are checked against a short list: email, uri, date, date-time, time, ipv4, ipv6 and uuid. Detection needs a full match, so ops@toolexe.com becomes email but "contact ops@toolexe.com first" does not. Hostnames without a scheme, such as api.toolexe.com, are left as plain strings on purpose. The hostname format is loose enough to match ordinary words, and a false positive there costs more than a missed one.
Lists: every item, then a merge
The shortcut most generators take is to type a list from its first item. This page reads all of them and merges. Two objects merge property by property. An integer and a float merge to number. Two strings with different formats merge to a string with no format. When the items share nothing, such as a list of [8080, "auto"], the output is "items": {"anyOf": [...]}, and an amber row asks whether the mix is intentional. An empty list produces "items": {}, because there is nothing to infer from, and that row is amber too.
owners:- name: Maya Lindqvist
email: maya@toolexe.com
pager: true
- name: Tomasz Wierzbicki
email: tomasz@toolexe.com
- name: Ifeoma Adeyemi
email: ifeoma@toolexe.com
pager: false"items": {"type": "object","properties": {"name": { "type": "string" },"email": { "type": "string", "format": "email" },"pager": { "type": "boolean" }},"required": ["name", "email"]}Anchors, aliases and merge keys leave no trace
YAML lets you define a block once with &base and reuse it with *base or <<: *base. The parser resolves these before returning data, so a document with one anchor and five aliases produces the same schema as one where the block was pasted five times. There is no $ref in the output pointing at a shared definition. If you want reuse in the schema, move the repeated object into $defs by hand after generating. The generator cannot tell a copied block from a referenced one once the parser is done.
What the draft selector changes
Three values are offered: draft-07, 2019-09 and 2020-12. The generator emits only keywords whose meaning is identical across all three, so the visible difference is the $schema URL and nothing else. That is deliberate. The keywords that changed between drafts, definitions becoming $defs and array items splitting into prefixItems, are not ones this page writes. Pick the draft your validator expects. Ajv 8 defaults to draft-07 and needs a separate import for 2020-12. Most OpenAPI 3.1 tooling expects 2020-12. Older Java and .NET validators often stop at draft-07.
A worked example
The sample loaded by the button is a deploy config for api.toolexe.com. Load it and read the panel. You should see an info row for version: 2.0 explaining why the type is number rather than integer, an amber row for the unquoted released date, another for mode: 0755 arriving as 755, an amber row for the empty sidecars list, an info row for the email format on owners[].email, and a required list on owners items that omits pager. Each row names a path you can search for in the output.
Where this generator stops
Everything below needs knowledge a single sample cannot carry. Add these by hand after generating.
- Enums.
region: eu-west-1is one allowed value out of a set you know and the page does not. Write theenumyourself. - Ranges and lengths. No
minimum,maximum,minLengthorminItemsis emitted. The sample shows one point, not a boundary. - Patterns. A string that looks like a version number or an ARN is typed as a plain string. Add
patternwhen the format list does not cover the case. - Discriminated unions. A list where each item has a
kindkey deciding the rest of its shape comes out as one merged object with most keys optional. Rewrite it asoneOfwith aconstonkind. - Multi-document files. A stream with
---separators is read, and only the first document feeds the schema. The panel says how many were skipped. Split the file, or generate one schema per document type. - Custom tags.
!Ref,!Suband other CloudFormation or application tags are unknown to the parser and stop the load with an error. Strip them, or use a schema published by the tool that defines them.
If the source of truth is already JSON, the JSON to JSON Schema page does the same inference without the YAML scalar resolution described above, which removes the date and octal cases entirely. If the file will not parse at all, run it through the YAML validator first, which reports the line and column instead of a bare error message.
The output is a first draft, not a contract. Generate it, read the amber rows, tighten what you know, and then validate a second real file against it before anything depends on the result.
