CalcCafe

YAML to Haskell

Paste YAML and get ready-to-use Haskell record types with inferred field types and nested data declarations.

Example

Input YAML:

name: Ada
age: 36
address:
 city: London
 zip: NW1

Generated Haskell:

data Address = Address
 { addressCity :: String
 , addressZip :: String
 } deriving (Show, Eq)

data Root = Root
 { rootName :: String
 , rootAge :: Int
 , rootAddress :: Address
 } deriving (Show, Eq)

How it works

The tool parses your YAML with js-yaml into a value, infers a type model (handling nested objects, arrays, numbers, booleans and nulls), then emits Haskell record syntax with deriving (Show, Eq). The root type is named Root.

Good to know

YAML to Haskell takes a YAML document and turns it into idiomatic Haskell record types, complete with a data declaration for the root value and a separate declaration for every nested mapping. It is aimed at Haskell developers who need to read config files, API payloads, or fixtures that already exist as YAML and want a typed scaffold instead of hand-writing each record and guessing at field types.

Reach for it when you are wiring up a config-driven program, modeling a third-party YAML schema, or porting sample data into a typed codebase. It saves the tedious first pass: it walks the parsed value and infers a type per field, so you start from a compiling skeleton rather than a blank file. Because everything runs in your browser via js-yaml, you can paste internal or sensitive configuration without it leaving your machine.

To read the output, note the conventions it applies. The root type is always named Root, nested objects get a type named after their key (capitalized), and field names are camelCased and prefixed with the lowercased type name (so city inside an address becomes addressCity). Dependencies are emitted before the types that use them, every type derives (Show, Eq), and list types are inferred from the first element only.

Frequently asked questions

How are nested objects and lists handled?
Each nested mapping becomes its own data declaration emitted before the type that uses it, so dependencies compile in order. Lists become Haskell list types like [Int] or [Address], inferred from the first element.
What happens with null values or numbers?
A null (or YAML ~) becomes Maybe Value since the concrete type is unknown. Whole numbers infer to Int and numbers with a decimal point infer to Double, while true/false become Bool.
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 the generated Haskell code use record field name prefixes to avoid collisions?
Yes. Each field is prefixed with the lowercased type name, so a field named city in an Address type is emitted as addressCity. This sidesteps Haskell's classic problem of duplicate record selectors clashing across types in the same module.
Will the output compile without any extra GHC language extensions?
The basic records and deriving (Show, Eq) it emits are standard Haskell 2010 and need no extensions. You would only add extensions yourself if you later rewrite it to use features like DuplicateRecordFields or DeriveGeneric for JSON parsing.
Can I use the generated types directly with a YAML or JSON parser like aeson?
Not as-is; the tool only produces the data type definitions, not FromJSON or FromYAML instances. You would add deriving Generic plus the relevant instances, or write them manually, to actually decode data into these records.
How does it decide between Int and Double for numbers?
It checks whether the parsed number is a whole integer or has a fractional part. Whole numbers infer to Int and numbers with a decimal point infer to Double.
What does it do when a list is empty or has mixed types?
An empty list becomes [Value] because there is no element to inspect, and for a non-empty list the element type is taken only from the first item. Mixed-type lists may therefore produce an inaccurate element type that you need to correct.
Is YAML to Haskell free and does it require an account?
Yes, it is completely free with no sign-up, and no usage limits. It runs entirely client-side in your browser and works offline once the page has loaded.
Why is the top-level type always called Root?
The tool assigns a fixed name, Root, to the outermost YAML mapping because top-level YAML documents have no inherent key to name them after. You can rename it afterward in your editor if you prefer a domain-specific name.

Related tools