SQL to YAML Converter

Turn INSERT statements from a dump, a migration or a seed file into YAML you would be happy to commit. Four output shapes, quoting that protects country codes and times from being read as booleans and numbers, and a note panel that tells you what the parser changed.

SQL to YAML conversion workspace

  • Type traps quoted for you
  • Block scalars for text
  • Nothing leaves the tab
SQL inputINSERT and REPLACE statements
Waiting for SQL0 tables0 rows0 keys written0 B output
YAML outputread only

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: 900

Multi-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: 900

The 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 databaseWritten bareWhat a 1.1 parser returns
NO (country code)country: NOFalse, not the string NO
y or n (single letter flag)flag: nFalse in PyYAML, a string in some others
on or offmode: offFalse
08:30 (a shift time)zone: 08:30510, the sexagesimal integer 8 times 60 plus 30
007 (a padded code)code: 0077 in some parsers, an octal error in others
1.2.3 (a version)ver: 1.2.3A string, but 1.20 silently becomes 1.2
2026-03-04day: 2026-03-04A 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.

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 parts

The | 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.

Indented under the key
users:- id: 1
name: Ann
- id: 2
name: Kofi
Level with the key
users:- id: 1
name: Ann
- id: 2
name: Kofi

Pick 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

Limits worth knowing before you paste

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.

Questions about converting SQL to YAML

Quoting rules, type surprises, fixture shapes, dialect support and what the parser skips.

Why did my country code NO come out with quotes around it?

Because YAML 1.1 reads the bare word NO as the boolean false, and PyYAML, Ruby Psych and SnakeYAML all still default to that behaviour. Writing country: "NO" is the only way the string survives every parser. The same protection covers y, n, on, off, yes, no, true and false in any casing, values that look like numbers or dates, and times such as 08:30 that would otherwise be read as sexagesimal integers. Each column where quoting stepped in is listed in the note panel under the editors.

What is the difference between the four output shapes?

Nested map gives one top-level key per table holding a sequence of rows, which suits seeders and import scripts. Fixture keys names each row table_1, table_2 and so on, which is what Rails fixtures and any loader that cross-references records by name expects. Flat list drops the grouping into a single sequence and adds a _table field when several tables are present. Multi-document separates each table with a --- marker for streaming parsers. All four hold the same data.

Should the dash be indented or level with the key?

Both parse identically. Indented reads better for a human reviewing a pull request because the nesting is visible. Flush with the key is what PyYAML, kubectl and most automatic dumpers emit, so choosing it stops a whole-file diff the next time a tool rewrites the file. Match whatever the repository already contains rather than picking on taste.

How are numbers and booleans decided?

By whether the value was quoted in your SQL. In the default mode an unquoted 42 becomes a YAML integer and a quoted 42 becomes a string, matching what the columns hold. Bare TRUE, FALSE and NULL become the YAML equivalents. Switch scalars to keep everything as text when the consumer does its own type handling or a numeric-looking key has to stay a string.

What happens to a text column containing line breaks?

In block style it is written as a literal block scalar using the pipe with a strip indicator, so the newlines survive and no trailing break is added that the column did not have. Turning on flow style rows forces the value onto one line as a double-quoted scalar with escapes, because a flow mapping cannot span lines. Tabs and other control characters are always quoted, since a block scalar cannot carry them safely.

Does it read Postgres or SQL Server dumps, not only MySQL?

Yes, as far as INSERT syntax goes. Backtick, double-quote and square-bracket identifiers are stripped from names, schema prefixes such as dbo.Orders or public.users are kept, and INSERT IGNORE, INSERT OR REPLACE and REPLACE INTO are treated as ordinary inserts. Doubled apostrophes and backslash escapes inside string literals are both handled. A Postgres COPY block is not an INSERT, so it is skipped without a message.

My dump has three tables. Do I get three files?

One file, unless you ask otherwise. Nested map, fixture keys and flat list put every table into a single document. Multi-document keeps them in one file separated by --- markers. Uncheck Every table to output only the table picked in the Table selector, and the download is named after that table instead of sql-data.

Is my SQL sent to a server?

No. Parsing, YAML generation, the preview, copy and download all happen in your browser after the page loads. No request carries your input, nothing is stored between visits, and closing the tab clears both editors.