A row of SQL is already a YAML mapping
Column names on the left, values on the right, one record per entry. The translation looks free until a value like NO lands in the file without quotes and a YAML 1.1 parser hands your application the boolean false instead of a country code. That single class of bug is what most of the settings above exist to prevent.
What gets read: INSERT and REPLACE statements holding literal value tuples. A CREATE TABLE block, an INSERT ... SELECT, a stored procedure body or a Postgres COPY section is skipped in silence. Comments are stripped before parsing, so a dump with a header block still works. If your file is mostly schema, run it through the SQL formatter first to see what is left.
Four shapes, one set of rows
The tabs at the top of the workspace rearrange the same parsed data. Pick by what reads the file next, not by which looks tidiest.
Nested map
Each table name becomes a top-level key holding a sequence of rows. This is what a Laravel seeder, a Symfony fixture loader or a hand-written import script expects when one file covers several tables.
warehouse_bins:- bin: A-01
country: "NO"
zone: "08:30"Fixture keys
Rows become named entries instead of an anonymous list, keyed table_1, table_2 and so on. Rails fixtures and any loader that lets one record reference another by name need this shape.
warehouse_bins:warehouse_bin_1:bin: A-01
country: "NO"Flat list
One sequence at the root with no table grouping. When more than one table is in play each record carries a _table field first, which suits a queue payload or a script that iterates once over everything.
- _table: warehouse_bins
bin: A-01
- _table: shipments
id: 900Multi-document
A --- marker starts a new document for each table in a single stream. Tools that read with yaml.safe_load_all or a streaming parser handle each table separately without loading the whole file.
---
warehouse_bins:- bin: A-01
---
shipments:- id: 900The Norway problem, and the rest of the family
YAML 1.1 treats a long list of bare words as booleans. YAML 1.2 narrowed it to true and false, but PyYAML, Psych in Ruby and SnakeYAML still ship 1.1 behaviour by default, so a bare word gets typed differently depending on who reads the file. These are the values that bite.
| Value in the database | Written bare | What a 1.1 parser returns |
|---|---|---|
NO (country code) | country: NO | False, not the string NO |
y or n (single letter flag) | flag: n | False in PyYAML, a string in some others |
on or off | mode: off | False |
08:30 (a shift time) | zone: 08:30 | 510, the sexagesimal integer 8 times 60 plus 30 |
007 (a padded code) | code: 007 | 7 in some parsers, an octal error in others |
1.2.3 (a version) | ver: 1.2.3 | A string, but 1.20 silently becomes 1.2 |
2026-03-04 | day: 2026-03-04 | A date object, not a string |
With quoting set to the default, every one of those is written with quotes and survives the round trip. The note panel under the editors names the columns where it stepped in, so you learn which fields in your schema are fragile rather than only getting a file that happens to work.
What SQL quoting tells the converter
The two typing modes read the same dump differently, and the difference comes from the quotes already in your SQL.
- Type unquoted literals.
VALUES (42, '42')gives42as a YAML integer and"42"as a string, matching what the database columns hold.TRUE,FALSEandNULLwritten bare in SQL become the YAML equivalents. - Keep everything as text. Every value except NULL is quoted. Pick this when the consumer parses types itself, when a fixture loader compares against string columns, or when a numeric-looking primary key needs to stay a string.
A number that arrives without quotes is written back exactly as you typed it. 249.50 keeps its trailing zero because the digits pass through as characters, not through a float. Scientific notation such as 1.5e3 also passes through unchanged, which some strict 1.1 parsers read as a string rather than a float.
Text with newlines gets a block scalar
A product description or a log message holding line breaks does not belong on one line with \n escapes. In block style the value is written as a literal scalar instead.
note: |-
damaged rail
awaiting partsThe | keeps the newlines, the - strips the final one so the string does not gain a trailing break that was never in the column. Turning on flow style rows overrides this, since a flow mapping has to sit on one line, and the text falls back to a double-quoted scalar with escapes. Values holding a tab, a carriage return or another control character are always quoted, because a literal block cannot carry them safely.
Where the dash goes
Both of these parse to the same structure. Neither is more correct.
users:- id: 1
name: Ann
- id: 2
name: Kofiusers:- id: 1
name: Ann
- id: 2
name: KofiPick the indented form when a human reviews the file in a pull request, since the nesting is visible at a glance. Pick the flush form to match what most YAML dumpers emit, including PyYAML and kubectl output, so your generated file does not produce a whole-file diff the next time a tool rewrites it. Match whatever the repository already uses.
Column names that need quoting
YAML keys are freer than XML element names, so a column called 2nd_line or order total stays readable. Quotes appear on a key only where the syntax demands them: a name holding a colon followed by a space, a leading indicator character such as -, ?, # or &, or a name that would itself read as a boolean or a number. Table names keep their schema prefix, so shop.orders and archive.orders stay separate keys and never merge.
Duplicate column names in one INSERT are a different matter. A YAML mapping holds each key once, so the last value wins and earlier ones are lost. The note panel flags it when it happens, because the file will still parse cleanly and give you the wrong data.
An INSERT with no column list
Dumps from mysqldump --compact often drop column names and rely on table order. Nothing in the statement carries a name, so fields read column_1 through column_n based on the widest tuple. If an earlier INSERT for the same table did carry a column list, those names are reused instead, which covers the usual pattern of one full statement followed by several short ones.
When YAML is the wrong target
- A machine-to-machine payload is safer as XML or JSON, where whitespace carries no meaning and no bare word changes type.
- Spreadsheets and one-off analysis want CSV, which drops all the structure you would be paying for here.
- A table for a ticket, a wiki page or a review comment is a job for SQL to HTML.
- Building the schema before any rows exist belongs in the SQL table generator, which writes CREATE TABLE rather than reading INSERT.
Limits worth knowing before you paste
- No expression evaluation.
NOW(),UUID()and arithmetic arrive as the literal characters you typed. Nothing here connects to a database that would resolve them, so they land in the file as strings. - No binary decoding. A blob written as
0x89504E47stays that text. Re-encoding to base64 with a!!binarytag would be a guess at what the column held. - No foreign key awareness. Tables come out in the order they appear in your dump. A fixture loader that inserts children before parents will still fail on the constraint, so reorder the statements before converting.
- No anchors or aliases. Repeated values are written in full every time. Deduplicating with
&anchorand*aliasneeds a judgement about which repeats are the same fact, and this tool does not make it for you. - Large dumps slow the tab. Parsing and rendering run on the main thread. A few megabytes is fine. A production export belongs in a script on the server.
Nothing you paste is uploaded. Parsing, conversion, copy and download all run in JavaScript on this page, so a dump holding customer rows never leaves your machine. Check the result against a parser with the YAML validator before it reaches a deploy.
