How to convert excel to json for react seed data
- Step 1Lay the sheet out as a flat table — Put one record per row and one field per column, with a single clean header row at the top. The header cells become your object keys exactly as written (trimmed of surrounding spaces). Move the sheet you want to the first tab position — the converter only reads the first sheet and has no sheet selector.
- Step 2Drop the .xlsx or .xls file onto the converter — SheetJS parses the workbook in your browser. The dropzone accepts
.xlsxand.xls. For a.csvsource, use csv-to-json instead — it has delimiter detection and quote-aware parsing built for CSV. - Step 3Keep 'First row is header' on — Leave First row is header checked so row 1 supplies the keys. Turn it off only if your sheet has no header row — then keys become
col0,col1,col2… and you can rename them afterward with json-key-renamer. - Step 4Keep 'Infer types' on for component-ready primitives — With Infer types on, numbers, booleans, dates, and
nullarrive as native values. Turn it off only when your downstream code expects every field as a string — with inference off, empty cells becomenulland everything else is stringified. - Step 5Pick an indentation — Choose 2 spaces (default) for a readable
data/products.jsonyou will commit, or Minified for a compact file. 4 spaces matches some Prettier configs. The output is always a JSON array regardless of indentation. - Step 6Download and import into your component — Click Download JSON to save
<filename>.json, drop it indata/orpublic/, andimport products from "@/data/products.json". For Next.js, read it insidegetStaticPropsor import it directly in a Server Component. Validate first with json-validator if the data feeds a typed API.
The four real options
Every control the converter exposes, mapped to what it does to React seed output. There is no sheet selector, no key-wrapper, and no CSV output mode — output is always a flat JSON array from the first sheet.
| Option (UI label) | Default | Effect on output |
|---|---|---|
| First row is header | On | Row 1 cells become object keys (trimmed). Off → keys are col0, col1, … and row 1 becomes a data object too |
| Infer types | On | Numbers → 42, TRUE/FALSE → booleans, date cells → ISO strings, empty → null. Off → empty → null, everything else stringified |
| Skip empty rows | On | Rows where every cell is blank are dropped. Off → blank rows become objects with all-null values |
| Indentation | 2 spaces | Minified (no whitespace), 2 spaces, or 4 spaces. Purely cosmetic — same array, same values |
How cell values map to JSON (Infer types ON)
Type inference is per cell, not per column. A column with mixed content yields mixed JSON types — see the edge cases for the consequences.
| Excel cell | JSON value | Component usage note |
|---|---|---|
42 (number) | 42 | item.qty + 1 works without Number() |
TRUE / FALSE | true / false | item.featured && … works directly in JSX |
A real date cell (2026-06-10) | "2026-06-10T00:00:00.000Z" | Wrap in new Date(item.launchedAt) to format |
019 (text-formatted zip/SKU) | 19 if Excel stored it as a number; "019" only if the cell is text | Format the column as Text in Excel to keep leading zeros |
| Empty cell | null | Use item.note ?? "" to avoid rendering null |
12.50 (currency) | 12.5 | Trailing zero is dropped — format on display with toFixed(2) |
Free vs Pro limits for this tool
Excel to JSON is a Pro tool. The free tier lets you try it on small sheets; larger catalogues need Pro.
| Limit | Free | Pro |
|---|---|---|
| Max file size | 2 MB | 50 MB |
| Max rows (records) | 500 | 100,000 |
| Files per run | 1 | 5 |
Cookbook
Real spreadsheet → React seed-data conversions, with the exact JSON the converter produces. Sample data is illustrative.
Product catalogue → useState seed array
ExampleA planning spreadsheet with id, name, price, and an 'in stock' flag becomes a typed array. Numbers and booleans are inferred, so the array drops straight into component state.
Sheet (first row = header):
id | name | price | inStock
1 | Cyber Mug | 12.5 | TRUE
2 | Neon Sticker| 3 | FALSE
Output (Infer types ON, 2 spaces):
[
{ "id": 1, "name": "Cyber Mug", "price": 12.5, "inStock": true },
{ "id": 2, "name": "Neon Sticker", "price": 3, "inStock": false }
]
Usage:
const [products, setProducts] = useState(data);FAQ sheet with date cells for getStaticProps
ExampleAn FAQ sheet that includes a 'published' date column. Real Excel date cells serialize to ISO-8601 strings ready for new Date() in a Next.js page.
Sheet:
question | answer | published
Is it free? | Yes, up to 500… | 2026-06-01
Does it upload? | No, browser-only. | 2026-06-05
Output:
[
{ "question": "Is it free?", "answer": "Yes, up to 500…", "published": "2026-06-01T00:00:00.000Z" },
{ "question": "Does it upload?", "answer": "No, browser-only.", "published": "2026-06-05T00:00:00.000Z" }
]Keep everything as strings for a string-typed prop
ExampleWhen a component expects every field as a string (e.g. a generic <DataTable> that renders cells verbatim), turn Infer types OFF. Empty cells still become null.
Sheet:
code | qty | active
A-01 | 5 |
A-02 | 12 | TRUE
Output (Infer types OFF):
[
{ "code": "A-01", "qty": "5", "active": null },
{ "code": "A-02", "qty": "12", "active": "TRUE" }
]Sheet with no header row → col0/col1 keys
ExampleWhen the sheet has no header row, uncheck 'First row is header'. Keys become positional (col0, col1, …). Rename them afterward to match your component props.
Sheet (data only, no header):
Mug | 12.5
Sticker | 3
Output (First row is header OFF):
[
{ "col0": "Mug", "col1": 12.5 },
{ "col0": "Sticker", "col1": 3 }
]
Next: rename col0→name, col1→price with /tool/json-key-renamerWrapping the array yourself for a Zustand slice
ExampleThe converter never wraps the array in a named key. If your Zustand store expects { products: [...] }, wrap it in one line after import — the tool gives you the inner array.
Converter output (always a bare array):
[ { "id": 1, "name": "Cyber Mug" } ]
In your store:
import products from "@/data/products.json";
const useStore = create(() => ({ products }));
// → { products: [ { id: 1, name: "Cyber Mug" } ] }Errors and edge cases
Real errors and silent failures sourced from each platform's own documentation. Match the wording to the row, fix what the row says to fix.
Only the first sheet is converted
By designThe converter reads the first sheet of the workbook and ignores the rest — there is no sheet picker in the UI. To convert a different tab, move it to the first position in Excel (or copy it into a new single-sheet workbook) and re-drop the file. Convert each sheet separately and import each resulting JSON file independently.
Output is always a flat array, never a wrapped object
By designThere is no option to wrap the result in a named key like { products: [...] }. The tool emits a bare JSON array of objects. If your store or API needs a wrapper, add it in one line after importing the JSON, as shown in the cookbook.
Leading zeros lost on SKUs / zip codes
Excel coercionIf Excel stored a value like 00742 as a number, the leading zeros are already gone in the workbook before the converter ever sees it — with Infer types on, you get 742. Fix it at the source: format the column as Text in Excel before saving, so the cell holds the string "00742". The converter then preserves it verbatim.
Merged cells leave blanks in every sub-cell but the first
Excel coercionExcel writes a merged value only into the top-left cell; the other cells in the merge export as empty (→ null). Unmerge cells before converting, or fill the value down across the merged range first. The converter has no merge-aware fill — it reads the raw cell grid.
Blank header cell becomes col0/col1
PreservedIf a header cell is empty (or all-whitespace) while 'First row is header' is on, that column's key falls back to its positional name col<index> (e.g. col3). This keeps every column addressable. Rename it afterward with json-key-renamer.
Duplicate header names collide
OverwriteIf two columns share the same header text (e.g. two name columns), they map to the same object key and the later column overwrites the earlier one in each object. Give every column a unique header before converting — JSON objects cannot hold duplicate keys.
Mixed-type column yields mixed JSON types
PreservedInference is per cell, so a column with 5, N/A, 12 produces 5 (number), "N/A" (string), 12 (number). If your component's prop type is strict, this breaks typeof assumptions. Clean the column to one type in Excel, or turn Infer types off to get all strings.
Free tier row / size cap exceeded
Upgrade requiredFree tier caps this Pro tool at 2 MB and 500 rows; Pro raises it to 50 MB and 100,000 rows. A large catalogue export will be blocked on free with an upgrade prompt. For a one-off, trim the sheet to under 500 rows, or split it and recombine the JSON arrays with json-object-merger.
Formula cells export as their computed value
ExpectedA cell with =A2*B2 exports as the cached computed number (Excel stores both), so the converter sees the value, not the formula. If the workbook was saved without recalculating, the cached value may be stale — open and re-save in Excel to refresh before converting.
Date shows as a serial number instead of an ISO string
Excel coercionIf a date column is formatted as General or Number in Excel, the cell holds the raw serial (e.g. 46184) rather than a date, so inference returns a number, not an ISO string. Re-format the column as a Date type in Excel before saving so SheetJS reads it as a date.
Frequently asked questions
Why is my output an array and not an object with a named key?
The converter always emits a bare JSON array of objects — there is no UI option to wrap it in { products: [...] }. This is the most direct shape for useState([...]) or a data/*.json import. If your Zustand slice or API needs a wrapper, add it in one line after importing the JSON, as shown in the cookbook.
Can I convert a specific sheet from a multi-sheet workbook?
The tool reads the first sheet only and has no sheet selector. Move the sheet you want to the first tab position in Excel (or copy it into a new single-sheet file) and re-drop it. Convert each sheet separately and import each JSON file independently in your React project.
How do I keep numeric IDs as numbers but a phone column as a string?
Inference is per cell, not per column, so there is no per-column toggle. Format the phone column as Text in Excel so its cells hold strings, then leave Infer types on — numeric IDs still infer to numbers while the text-formatted phone column stays a string. Alternatively, convert with inference off (everything becomes a string) and cast only the ID fields in your component.
Does the spreadsheet leave my machine?
No. SheetJS parses the workbook entirely in your browser. The file, your unreleased catalogue, pricing, or customer data are never uploaded to JAD Apps or any third party — there is no server round-trip in the conversion path.
What file types does it accept?
.xlsx and .xls. For a .csv source, use csv-to-json instead — it is purpose-built for CSV with delimiter sniffing and RFC-4180 quote handling that a spreadsheet parser does not apply.
My dates came out as numbers like 46184 — why?
That column was formatted as General or Number in Excel, so the cell stores the underlying date serial rather than a date value. Re-format the column as a Date type in Excel and save again. SheetJS reads true date cells and the converter emits ISO-8601 strings like 2026-06-10T00:00:00.000Z.
How do I rename headers to camelCase for my component props?
The converter uses your header text verbatim (trimmed) and has no case-normalization option. Either rename the headers in Excel first, or convert as-is and run the output through json-key-renamer to map Product Name → productName across every object.
Why did a SKU like 00742 lose its leading zeros?
Excel coerced it to a number 742 when the cell was saved, before the converter saw it. Format the column as Text in Excel so the cell holds the literal string "00742", then convert — the value is preserved exactly.
What happens to empty cells?
They become null whether Infer types is on or off. In JSX, guard with item.field ?? "" so you never render the literal text null. If you would rather drop null keys entirely from each object, run the output through json-null-stripper.
Is there a row limit I should know about for a big catalogue?
Yes. This is a Pro tool: free tier allows up to 2 MB and 500 rows; Pro raises it to 50 MB and 100,000 rows. A large export will be blocked on free with an upgrade prompt. For a quick test, trim to under 500 rows; for production seeds, Pro handles the full file.
Can I validate the JSON before importing it into a typed component?
Yes — paste the output into json-validator to confirm it is well-formed. If you want a TypeScript interface for the array, feed one record into json-to-typescript and use the generated type on your useState and props.
Why are some price values like 12.50 showing as 12.5?
JSON numbers have no concept of trailing zeros — 12.50 and 12.5 are the same number, so the converter emits 12.5. Format prices for display at render time with value.toFixed(2). If you need the exact string "12.50" preserved, format that column as Text in Excel before converting.
Privacy first
Conversion runs locally in your browser. No file is uploaded — only metadata counters are saved for signed-in dashboard stats.