Convert TOML to YAML

Converting TOML to YAML renders a manifest such as pyproject.toml or Cargo.toml as the indented form a pipeline tool expects. It is the one target here that writes a TOML date without quotation marks, and the one where the type of every value stops being declared by the syntax and starts being resolved by whatever loads the file.

  • Where it runs In your browser. The file is never uploaded.
  • Lossless Nothing is discarded. The YAML holds exactly what the TOML held.
  • File size limit Up to 100 MB per file, free, without an account.

Up to 100 files at once. Mixed formats are fine.

Lifting manifest values into a pipeline that reads YAML

The facts about a project increasingly live in a TOML file — the package name, the supported Python or Rust versions, the feature flags, the dependency set. The things that consume those facts are, with the same consistency, YAML: a GitHub Actions workflow, a Helm values file, an Ansible variable set, a docker-compose service block. Nobody chose this split; it is what two ecosystems settled on independently.

So the job is usually not a migration but a transcription: get the values into YAML syntax accurately, then move the parts you need into a file that has a shape of its own. That distinction is worth holding on to, because it changes what "correct output" means. The output does not have to be a valid workflow. It has to be a faithful rendering you can lift from without retyping a version number.

TOML dates arrive unquoted, and the loader decides what they are

TOML is unusual among configuration formats in having real date and datetime types, written without quotation marks: `launch = 2026-03-01T08:00:00Z`, `day = 2026-03-01`, `at = 08:00:00`. They arrive in the YAML the same way — `launch: 2026-03-01T08:00:00.000Z`, `day: 2026-03-01`, `at: 08:00:00.000` — with no quotation marks around them, which is what YAML reserves for a timestamp. Convert the same manifest to JSON and you get the identical characters inside a pair of quotes, because JSON has one scalar type for text and nothing else to offer.

What that buys you depends entirely on the loader, and it is worth knowing before you rely on it. Read the output back with the same library that wrote it, which follows the YAML 1.2 core schema, and every one of those values comes back a string: 1.2 has no timestamp resolver. Read it with PyYAML or Ruby’s Psych, both still on YAML 1.1, and the first two become datetimes while `at: 08:00:00.000` resolves as the sexagesimal number 28800. An offset is normalised to UTC on the way in as well, so `2026-03-01T08:00:00+02:00` returns as 06:00:00Z. If a date has to survive as a date, say so at the destination rather than trusting the shape of the file.

Why YAML rather than XML for a manifest full of dates

Both targets write the same characters for a date, so the argument is about where the type lives. In the YAML the value is unquoted and self-describing enough that a 1.1 loader will type it without being told. In XML the same date is element text, and what it means comes from a schema somebody else maintains: `2026-03-01` has to be declared `xs:date` and `08:00:00.000` has to be declared `xs:time`, and a local time landing on an element declared `xs:dateTime` is a validation failure rather than a string you can shrug at.

That cuts both ways, which is why this is a paragraph and not a recommendation. A schema is an enforcement mechanism, and if the receiving system has one, a wrongly typed date is caught at the door instead of three steps into a pipeline. Choose YAML when the destination is a workflow or a values file that will read the value back with its own loader and you control which loader that is; choose XML when something downstream is going to validate the document and you would rather hear about the problem then.

How TOML tables are laid out once they are YAML

A `[package]` header becomes a top-level key with its values indented two spaces beneath it. A `[tool.black]` header becomes `tool:` containing `black:` containing the settings, because a dotted table header is nesting rather than a name with dots in it. Dotted keys behave the same way: `a.b = 1` becomes `a:` containing `b: 1`.

The order is the order the parser saw, which for TOML means the loose values at the top of the file come first and each table follows in the order it was written. That usually reads well, since TOML requires root-level keys to precede the first table header anyway. What does move is anything expressed with dotted keys scattered through the file — those are collected under one parent in the YAML, which is more readable and is not what the source text looked like.

TOML declares its types and YAML resolves them

This is the real change of régime and it is easy to miss because the output looks so similar. In TOML, `enabled = true` is a boolean because the syntax says so, and `version = "1.0"` is a string because it is quoted. Nothing is inferred and nothing can be misread. In YAML, an unquoted scalar is whatever the parser decides it is, which is why the writer has to quote defensively.

It does that where it matters: a string of digits comes out quoted, so `version = "1.0"` stays `version: "1.0"` and not the number 1. What it does not quote is `NO`, `yes`, `on` and `off`, because under YAML 1.2 those are ordinary strings and the file is written for a 1.2 parser. Load it with PyYAML or Ruby’s Psych, both of which still implement YAML 1.1, and they become booleans. A TOML author has never had to think about this, which is exactly why it is worth a paragraph here.

Arrays of tables become YAML lists of mappings

A repeated `[[bin]]` or `[[tool.poetry.packages]]` block is TOML’s list-of-records form, and it converts to the shape everyone writes by hand in YAML: a dash per entry, keys indented under it. Plain arrays behave the same way, one dashed line per element, and an array of scalars written inline in TOML comes out as a block list rather than as flow syntax.

That block form is what most YAML tools document and what most examples show, so entries usually paste into a workflow or a values file without reformatting. If the destination genuinely wants flow style — a matrix line written as `[3.11, 3.12, 3.13]` — that is a manual edit, and a small one.

Multi-line TOML strings arrive as YAML block scalars

A TOML triple-quoted string holding a script, a description or a licence excerpt keeps its line structure. The writer emits it as a block scalar — the key, then a pipe, then the real lines indented beneath — rather than as one line with escape sequences in it.

Long single-line values are handled differently: a string with no newlines but plenty of length is folded onto continuation lines at around eighty columns, and YAML reads those folds back as spaces, so the value is unchanged. It does mean a long URL can appear split across two lines in the file. That is disconcerting rather than damaging, and copying the value out of a loaded structure rather than out of the text avoids any doubt.

Both formats keep comments and this conversion keeps none

TOML and YAML each support `#` comments, and a manifest is usually full of them: why a dependency is pinned to a patch release, which of two settings is deliberate, what a magic number came from. None of it survives, because the reader discards comments on the way in and the writer has none to place on the way out.

For a fragment you are about to paste that is unremarkable. For anything you intend to keep, it is the reason the TOML stays the source of truth and the YAML is generated: two files with the same values and only one with the reasoning is a maintenance problem waiting to be discovered by whoever inherits it. If the YAML has to be committed, write a short comment at the top saying which manifest it came from and how to regenerate it.

YAML features a converted TOML file will never use

The output uses a plain subset of the language, and knowing which parts are absent saves time reading it. There are no anchors and no aliases — a repeated sub-table appears twice in full rather than once with a reference, because the parsed values are separate objects and nothing deduplicates them. There is no null anywhere, because TOML has no null to convert. There are no tags, no explicit types and no document separator; the file is one document.

If the destination expects any of those, you are adding them by hand. An Ansible variable set that relies on vault tags, or a Helm values file built around anchors to avoid repetition, is a file this conversion feeds into rather than produces. That is not a limitation of YAML; it is that the manifest never expressed those things and nothing can invent them.

Reading the YAML back before you rely on it

The cheapest check is a round trip. Load the output with whatever will eventually load it and compare a handful of values against the manifest — the version, one date, anything that looked like a number and is meant to be a string, and any value that is a bare word. Those four categories cover almost everything that can go quietly wrong.

`yq eval . out.yaml` reformats and reports a syntax error if there is one, and `python -c "import yaml,sys; print(yaml.safe_load(open('out.yaml')))"` shows you what a YAML 1.1 loader thinks the file says, which is the version of the truth that matters if the destination is Ansible or an older Kubernetes tool. Doing that once is faster than debugging a pipeline that ran with `version: 1` where you meant `"1.0"`.

Where the TOML file is converted

In this browser tab, by plain JavaScript. Nothing is uploaded, there is no engine to fetch first, there is no account and no daily allowance. Opening the network tab and converting something is how to confirm that, rather than taking this paragraph for it.

Manifests are small enough that the 100 MB free ceiling is theoretical, but they are not always public. A private repository’s dependency list names internal packages and internal registries, and a `[tool]` block sometimes carries hostnames or paths that say more about an organisation than anyone intends. Converting locally means none of that is a disclosure.

How to turn a TOML manifest into YAML

  1. Drop the .toml file onto this page, or click to choose it.
  2. Tables become indented mappings and arrays of tables become lists, in your browser.
  3. Lift what you need into the workflow or values file, and keep the TOML as the original.

TOML and YAML: declared types against resolved ones

TOML compared with YAML
TOMLYAML
Full nameTom's Obvious Minimal LanguageYAML Ain't Markup Language
File extension.toml.yaml, .yml
Media typeapplication/tomlapplication/yaml
First published20132001
SpecificationTOML 1.0YAML 1.2
LicensingOpen standardOpen standard
Standing todayCurrentCurrent
Opens in a browserNo browserNo browser
Considered insteadJSON, INIJSON

What survives

Nothing is discarded. TOML and YAML both store their content losslessly, so the conversion is a change of packaging rather than a change of quality, and it can be repeated without accumulating damage.

Comments carry across. Both TOML and YAML have a comment syntax, so notes left for whoever maintains the file next are not silently thrown away.

Opening the result

Visual Studio Code reads both TOML and YAML, so there is a way to check the result against the original without a second tool.

What each format is for

TOML was published in 2013. The specification is TOML 1.0, and it is worth reading if the file has to outlive the tool that wrote it.

YAML dates from 2001, specified as YAML 1.2. Visual Studio Code and yq all read it.

TOML to YAML: dates, lists and quoting

Are my TOML files uploaded anywhere?

No. This conversion runs entirely inside your browser, so the file never leaves your device. You can confirm it yourself: open the network tab of your browser's developer tools and convert something. You will see the page load, plus the analytics and advertising the site is paid for with — and nothing carrying your file.

Do TOML dates come back out of the YAML as dates?

They are written unquoted, which is the form YAML reserves for a timestamp and the only TOML target here that uses it. Whether a loader then types them is its decision, not the file’s: under YAML 1.2 there is no timestamp resolver and you get strings back, and under YAML 1.1 you get datetimes — but a bare local time such as 08:00:00.000 comes back as the number 28800.

Why does the YAML add milliseconds to my timestamp?

Because the value passes through a date object on the way, and it is written in full ISO form. 2026-03-01T08:00:00Z becomes 2026-03-01T08:00:00.000Z. It is the same instant; a loader parses both identically.

What happens to arrays of tables?

Each [[block]] becomes an entry in a YAML list, introduced by a dash, with its keys indented under it. That is the shape most YAML tools expect for a list of records, so it usually pastes straight in.

Are the comments carried across?

No. Both formats have comments and neither the reader nor the writer moves them, so every explanatory line in the manifest is missing from the YAML. In a file whose comments are half its value, that is worth deciding about rather than discovering.

Is a value of "no" or "on" safe in the YAML?

Under YAML 1.2, which the writer targets, yes — those are plain strings and are written unquoted. Under YAML 1.1, which PyYAML and Ruby’s Psych still implement, they are booleans. If the destination is one of those, quote them before loading.

Will the result be a valid workflow or values file?

Not on its own. What you get is a faithful YAML rendering of the manifest, and a workflow, a chart or a playbook has a required shape of its own. Treat the output as a fragment to lift from, not as the finished file.

More about these formats