Convert both ways, converting a type only when it reads back the same, and naming every value that cannot
Initializing in your browser…
Convert CSV to XLSX or ODS with cell types that keep leading zeros, long IDs and dates intact
Chain 34 cell transformations, each stating its own rule, with anything it could not do reported rather than passed through unchanged
Convert images between PNG, JPG, WebP, AVIF, BMP formats. Features quality control, transparency support, and batch conversion for efficient workflow.
An export holds a postcode with a leading zero, a note with a quote in it, and a padded field. Those three are exactly what a naive converter changes without saying so.
Input CSV
id,zip,note,pad 1,07030,"He said ""hi"""," spaced "
Output JSON
[
{
"id": 1,
"zip": "07030",
"note": "He said \"hi\"",
"pad": " spaced "
}
]id becomes the number 1 because writing 1 back gives exactly "1". zip stays a string because 7030 is not what the file said. The quote characters inside note are data and are left alone; the previous version stripped a quote from each end of every field, so this value arrived as He said "hi with the closing quote gone. The spaces around pad survive, because RFC 4180 section 2.4 says spaces are part of a field.
Convert a CSV file to JSON, or JSON back to CSV, with every value that cannot survive the trip named on the page. A CSV field is a string and JSON has types, so the interesting question is which conversions can be undone. By default a value becomes a number or a boolean only when writing it back out gives exactly the text the file held: 42 becomes the number 42, and 007, 1e5 and 0.10 stay strings, because 7, 100000 and 0.1 are not what the file said.
CSV and JSON model data differently. CSV is flat, rectangular and untyped: every field is a string and there is no way to express nesting, a missing value, or a number as distinct from the digits that spell it. JSON is hierarchical and typed. Converting between them means making decisions, and this tool states each one and counts what it cost.
**Types.** The default rule is reversibility. A token becomes a JSON number only if String(n) is the token again, which is exactly the algorithm JSON.stringify uses when writing it back, so a value that converts can always be recovered. That keeps postcodes, product codes, phone numbers, exponent notation and trailing decimal zeros as strings without a special case for any of them, and it keeps a 20 digit identifier intact where a double would round it. Only the exact tokens true and false become booleans, because JSON writes a boolean in lower case and TRUE would come back changed. The four letters NULL stay a string unless you ask for them to be null, and if you do, the page counts how many cells that changed and says a null writes back as an empty cell rather than as the word. A looser mode converts anything the decimal grammar accepts and reports every value it could not have undone.
**Spaces and quotes.** Fields are not trimmed by default, because RFC 4180 section 2.4 says spaces are part of a field and should not be ignored, and quote characters inside a value are left alone: a cell holding a quoted phrase arrives in the JSON with both quotes.
**Column names.** A JSON object cannot hold two members with the same name, so a duplicate header is renamed and reported rather than losing a column. An empty header stays an empty name, because that is legal JSON and it writes back out as an empty header. A field beyond what the header row names gets a numbered column and is counted, so a ragged file converts instead of failing.
**Shapes.** Array of objects is the default. There is also an object wrapping the array with a count, a keyed object indexed by a column you pick (where a repeated or empty key is reported rather than quietly replacing a row), one array per column, and a plain array of arrays that interprets nothing at all.
**Going back.** JSON to CSV builds the header from the union of every object’s keys in the order they first appear, so a field that only some objects carry is still a column. Nested objects flatten into dotted columns, and an array or anything else CSV has no shape for is written as JSON text inside the cell and counted. The output is RFC 4180: CRLF records, quoting applied wherever leaving it out would make the file unreadable, and a byte order mark so Excel reads it as UTF-8.
Get an array of objects with numbers as numbers, and with identifiers still spelled the way the file spelled them.
Flatten nested objects into dotted columns and keep every field, including the ones only some records carry.
The panel lists every value whose type cannot be undone, so you know before you commit rather than after.
A column of 07030, 00501, 90210 comes out as the strings "07030", "00501", "90210". The number 7030 is not what the file said, so it is not written.
A field written with doubled quotes, per RFC 4180 section 2.7, arrives in the JSON with both quote characters present rather than stripped.
Converting [{"a":1,"b":2},{"a":3,"c":4}] back to CSV gives the columns a, b and c. Taking only the first object’s keys would have lost c entirely.
Not by default. A value converts only when writing it back gives exactly the text the file held, and 7 is not 007. There is a looser mode if you want the conversion anyway, and it reports every value it changed.
It stays a string. A 20 digit identifier cannot be held exactly by a JSON number in any implementation that uses doubles, so writing it as one would change it. The reversibility rule catches this without a special case.
Only if you ask. A null written back into a CSV is an empty cell rather than the word, so the conversion cannot be undone, and the page counts how many cells it affected.
The second is renamed, for example to "name (2)", and the rename is reported. A JSON object cannot hold two members with the same name, so one of them has to change; losing the column instead would be worse.
They convert. The extra fields go into numbered columns and the count is reported. Nothing is dropped.
Rows and columns are parsed and transformed in memory in your browser. No record ever reaches a server.