Excel to JSON Lines Converter

Bulk-load a spreadsheet. One compact object per line, no wrapping array, and a key that is a string on the first line is a string on the hundred thousandth.

To convert Excel to JSON Lines, drop your .xlsx above. Each row of the chosen sheet becomes one compact JSON object on its own line, with no wrapping array and no commas between records. Each column carries one type on every line, which is what BigQuery, Snowflake, Redshift and DuckDB require of an NDJSON load. Blank cells become null.

Need to filter rows before the load? Open the app

Why a loader wants lines and not a document

A JSON array has to be parsed as a single value, which means the whole thing has to be in memory before any of it can be used. Newline-delimited records can be read one line at a time, forever, which is why every warehouse loader and every log shipper converged on the same shape.

It also means a broken file fails late and expensively. The loader gets through two million rows and then hits the one line whose schema disagrees, and rolls the whole load back. Everything on this page is about not producing that line.

Worked example

A sheet with the columns that catch converters out:

store_code   opened_on    staff   revenue   active
0041         2019-03-04   12      1840.50   TRUE
0058         2020-07-19   7       975.00    FALSE

And the JSON Lines:

{"store_code":"0041","opened_on":"2019-03-04","staff":12,"revenue":1840.5,"active":true}
{"store_code":"0058","opened_on":"2020-07-19","staff":7,"revenue":975,"active":false}

store_code is a string on both lines because of the padding. active is a real boolean, because Excel's TRUE is a boolean rather than the word. revenue is a number here, unlike the CSV case, because Excel stored 1840.5 and painted the trailing zero: the value never had one.

opened_on is a string, and deliberately. A warehouse will parse it into a DATE using the column type you declare, and emitting a timestamp here would attach a timezone nobody chose.

The failure this avoids

The leading free converter on this term types each cell independently. Its own NDJSON output, from a single file, contains this:

{"id":2,"zip":94043,"amount":80}
{"id":1,"zip":"01730","amount":"120.50"}

zip is a number on one line and a string on the next, and so is amount. Every consumer named on that converter's own page rejects this. Their sibling JSON page gets it right, which means one emitter skipped the profiling step.

Here the typing happens once, in one place, before any writer is involved, and every target on this site shares it. The JSON Lines file agrees with the CSV, the workbook, the Parquet and the SQL script.

Notes for a real load

  • Declare the schema. Autodetection samples the first few hundred lines, so a column that is empty early gets typed from row 1001. The preview here shows you every column; write the schema from it.
  • Padded codes need STRING columns. If the target declares store_code as an integer, the load succeeds and the zeros are gone. This file has the right value; the schema has to accept it.
  • Every object carries every key. A blank cell is null, not a missing key, because a fixed-schema loader treats those differently.
  • Dates as strings. Declare the column as DATE and let the warehouse parse it, which is the only place the timezone question has a correct answer.
  • One sheet per file. A single NDJSON file holding two shapes is not something any loader can use.

Sheets, formulas and the things a workbook hides

A workbook is not one table. It is a data sheet, a notes tab, a pivot somebody built for a meeting in 2023 and an empty Sheet3. The first sheet with data converts on arrival and every sheet name is listed under the result, so switching is a click rather than a modal you have to answer before you see anything.

Formulas come through as their computed values, which is what the sheet shows and what a loader can use. A formula that currently evaluates to an error, such as a broken lookup, comes through as the error text, which is deliberately visible rather than silently blanked: a row that says #N/A is a row you can find and fix.

Merged cells contribute their value to the top-left position of the merge and leave the rest blank, because that is what the file itself records. A merged header row is the usual reason a converted sheet has a column called column_4 in it, and the note under the result says so rather than leaving you to work it out from the JSON.

Hidden rows and hidden columns are included. They are data, and a load that silently omitted them would be worse than one that includes something you did not want. Delete them in the sheet, or filter them out in the full editor, if they should not travel.

When an array is the better answer

If a person or an API is going to read the result, use the array. The Excel to JSON page emits one, with the same typing behind it, so the only difference is punctuation.

The rule of thumb: lines for machines, an array for anything you would open in an editor. The crossover is roughly the point at which the file stops being something you would scroll through.

Frequently Asked Questions

Is JSON Lines the same as NDJSON?

Yes. Two names for one convention, one JSON value per line separated by newlines. Both the .jsonl and .ndjson extensions are in use and every tool that reads one reads the other.

Will this pass a warehouse schema check?

That is the point of the typing rule. Every column gets one type from all of its values, so no key changes type between lines. Declare the schema rather than autodetecting it, since autodetection only samples the first few hundred lines.

Why is a value that showed as 1,840.50 written as 1840.5?

Because Excel stored 1840.5 and painted the format. The comma and the trailing zero were never part of the value. This differs from the CSV case, where the trailing zero is real text and keeps the column as strings.

What happens to blank cells?

They become null, and the key is still present on every object. A missing key and a null value mean different things to a fixed-schema loader, and only one of them is what your sheet says.

Are dates emitted as timestamps?

No, as ISO date strings. Declare the target column as DATE and let the warehouse parse it. Emitting a timestamp here would attach a timezone that nobody in the chain actually chose.

Can I get a single array instead?

Yes, the Excel to JSON page produces one with the same typing decisions. Use an array when a person or an API reads the result, and lines when a loader consumes it.

Get the sheet ready for the warehouse

One object per line, one type per column, real nulls. No array to hold in memory.

Back to the converter