Markdown Table to YAML Converter

The settings were agreed in a document and the application reads YAML. Paste the table, get a list of mappings with one type per column and quotes where a parser needs them.

To convert a Markdown table to YAML, paste the table above. Each row becomes a mapping in a YAML sequence, keyed by the header cells, with a type decided once per column. Empty cells become null, and any value a YAML reader would coerce into something else, dates and padded codes and the word no among them, is quoted so it survives.

Want to drop a column before you generate the file? Open the app

The table in the design doc becomes the config

The sequence is familiar. Somebody writes a design document with a table in it: five services, their replica counts, their log levels, which region they run in. The table gets reviewed, the numbers get argued over, and then the table has to become a file the deployment actually reads.

Re-typing it is where mistakes enter. A replica count transposed from 12 to 21 in a config is a bad afternoon, and it is exactly the sort of error that a review of the document would never catch because the document is right.

So convert rather than re-type. The table you reviewed becomes the file you deploy, character for character.

Worked example

The table from the runbook:

| service | version | released | replicas | notes |
|:--------|--------:|:--------:|---------:|:------|
| billing-api | 2.4.1 | 2026-01-08 | 6 | rollout paused |
| web-frontend | 5.0.0 | 2026-01-12 | 4 | canary 10% \| full 14 Jan |
| search-index | 1.19.3 | 2026-01-15 | 12 | |

And the YAML:

- service: billing-api
  version: '2.4.1'
  released: '2026-01-08'
  replicas: 6
  notes: rollout paused
- service: web-frontend
  version: '5.0.0'
  released: '2026-01-12'
  replicas: 4
  notes: canary 10% | full 14 Jan
- service: search-index
  version: '1.19.3'
  released: '2026-01-15'
  replicas: 12
  notes: null

Every quote in that output has a reason. '2026-01-08' unquoted is a YAML 1.1 timestamp, so the loader hands your deployment script a date object where the config said a string. The versions are quoted because 5.0.0 is ambiguous enough that some readers try, and because a version that silently became a float would compare wrongly. billing-api and rollout paused are bare, because a file where everything is quoted is a file nobody proofreads.

The values YAML quietly changes

The classic is Norway. Its country code is no, and unquoted in YAML 1.1 that is the boolean false, so a country list generated carelessly is missing one entry and has a false where it should be. The same family catches yes, y, n, on, off and ~.

The second family is anything that reads as a number without being one. A cost centre of 01730 loses its zero. A version of 1.10 becomes 1.1. A build tag of 1e5 becomes 100000.

Quoting is decided per value, from what that exact text would resolve to, which is why one column can hold a bare `se` next to a quoted `'no'`. It looks uneven and it is precisely correct.

Types, nulls, and the shape of the file

A column becomes numbers only when every value in it round trips exactly, so 6 and 12 qualify and 6.0 would not. Deciding once per column is what stops a list where replicas is a number in three entries and a string in the fourth.

An empty Markdown cell becomes null rather than an empty string. In a config that distinction almost always decides whether a default applies, and it is the difference between "no override" and "override with nothing".

The output is a flat sequence of mappings, always. No top-level key wrapping the list, no grouping by a column. Both of those are guesses about your consumer, and adding a wrapping key by hand takes two seconds while unpicking a wrong one does not.

Round trips

The shape here is the one our YAML to CSV tool reads back into the same rows, which makes a useful loop: keep the table in the document, generate the config, and when someone edits the config directly, convert it back to see the table in the review.

No attribution comment is added to the file. Two of the free converters on this term stamp a generated-by line into every YAML they write, one of them with no way to turn it off. Your config is yours.

Frequently Asked Questions

Why are the dates in quotes?

Because a bare 2026-01-08 is a YAML 1.1 timestamp, and PyYAML and friends will hand your code a date object where the config said a string. Quoting keeps it a string. A competing converter emits these bare on a page whose FAQ claims it does not.

Why is one value quoted and the next one bare in the same column?

Quoting is per value, based on what that exact text would resolve to. In a country column, no is the boolean false in YAML 1.1 and must be quoted, while se is unambiguous. Quoting everything would be safe and would make the file unreadable.

What do empty cells become?

Real nulls, not empty strings. In a config that difference usually decides whether a default applies, so it is the one place where being pedantic pays off immediately.

Can I get a top-level key above the list?

Not as an option. The output is always a flat sequence of mappings, which is what most loaders expect and what our YAML to CSV tool reads back. Adding a wrapping key and indenting is a quick edit; guessing wrong about your structure is not.

Is a comment added to the output?

No. Nothing is inserted into your file. Some free converters stamp a generated-by line into every YAML and SQL file they emit, and only one of those lets you turn it off.

Does a header with a dot in it create nesting?

No. A header called limits.retries becomes a key spelled limits.retries. Building structure out of punctuation is a guess, and it breaks any header that legitimately contains a dot.

Turn the reviewed table into the deployed file

One mapping per row, one type per column, quotes exactly where a parser needs them.

Back to the converter