gizmobench
BrowseDaily
← All guides

GizmoBench guides

CSV to JSON Tutorial: Convert Files Correctly and Safely

GizmoBench ·

Converting CSV to JSON means reading the first row as field names, turning every following row into an object, and wrapping the objects in an array. The mechanical part takes a few lines of code in a browser, in Python or in a spreadsheet-driven workflow. The harder part is everything the CSV format leaves unspecified: quoted commas, line breaks inside cells, and the fact that every value arrives as text. This tutorial covers the full path, from cleaning the source to checking the result.

We focus on methods that run locally, because CSV files often hold customer lists, payroll exports or other data you may not want to upload to a stranger’s server.

GizmoBench
Convert CSV Files in Your Browser
Explore browser-based tools for working with files, with processing done locally in your browser and no account or software installation required.
Explore online tools

TL;DR

  • A CSV header row becomes the keys of each JSON object, so clean and de-duplicate the headers before you convert.
  • Never split lines on commas yourself. Use a real parser: Papa Parse in the browser, csv.DictReader or pandas in Python.
  • CSV has no data types, so decide deliberately whether 007, 1e5 and TRUE should stay strings or become numbers and booleans.
  • Validate the output afterward: format it, inspect it, and optionally infer a JSON Schema to catch inconsistent rows.
  • For private data, prefer tools and scripts that process the file on your own machine.

Table of Contents

What the conversion actually does

Take a small CSV file:

id,name,city,note
1,Ana Ruiz,Austin,"Likes tea, not coffee"
2,Li Wei,Denver,

The most common JSON output is an array of objects, one per row:

[
  { "id": "1", "name": "Ana Ruiz", "city": "Austin", "note": "Likes tea, not coffee" },
  { "id": "2", "name": "Li Wei", "city": "Denver", "note": "" }
]

Three details in that output deserve attention before you write any code.

  1. The comma inside the first note did not split the field, because the cell was wrapped in double quotes.
  2. The id values are strings ("1"), not numbers, because a CSV file stores only text.
  3. The empty note became an empty string. Whether it should be "", null or a missing key is your decision, and it should be consistent.

An alternative shape is an array of arrays, which keeps the header as the first inner array. It is smaller on disk but forces whoever reads it to track column positions, so most APIs and web apps prefer the array of objects.

Step 1: Clean the CSV first

The JSON you get can only be as tidy as the headers you start with. Practitioners writing converter guides, such as this CSV to JSON walkthrough, recommend opening the file in a spreadsheet application such as LibreOffice Calc or Microsoft Excel first, to remove columns you do not need and to check the header row.

A short checklist:

  • One header row, at the top. Delete title rows, report dates and blank lines above it.
  • Unique header names. Two columns named price will collide, because an object cannot hold the same key twice. Rename one.
  • Keys you can live with. Names like First Name work, but first_name or firstName are easier to use in code later.
  • No trailing summary rows. Totals at the bottom of a spreadsheet export become a bogus record.
  • Text columns kept as text. If an identifier such as a ZIP code or product SKU has leading zeros, make sure your spreadsheet did not already strip them. If your source is an Excel workbook rather than a CSV, our spreadsheet converter lets you pick a sheet and keep text as text when exporting to CSV.

Step 2: Decide the shape and the types

Make two decisions before you convert, and write them down if the file will be converted repeatedly.

Shape. Array of objects is the default. If one column is a unique key (an id, say), you may prefer an object keyed by that column, which gives instant lookup but cannot represent duplicate keys.

Types. Every CSV cell is text. A parser can leave it that way or guess. Guessing is convenient and occasionally destructive:

Cell value Safe as string? Risk if converted to a number or boolean
007 Yes Becomes 7, losing the leading zeros
12345678901234567890 Yes Exceeds the precision JavaScript numbers can hold exactly, so digits can change
1e5 Yes Becomes 100000, which may be a product code, not a quantity
TRUE / yes Depends A parser may or may not treat these as booleans
(empty) Depends Could be "", null or an omitted key

A workable rule: keep everything as a string by default, then convert only the columns you know are numeric or boolean. Identifiers are text even when they look like numbers.

Step 3: Convert it

The right method depends on where the file lives and who will repeat the job.

In the browser with JavaScript

The usual tool for client-side parsing is Papa Parse. Its documentation covers converting delimited text to JSON from strings or files, and local files are opened with the browser’s FileReader, so nothing has to leave the machine. A minimal version looks like this:

const input = document.querySelector('#file');
input.addEventListener('change', () => {
  Papa.parse(input.files[0], {
    header: true,
    skipEmptyLines: true,
    complete: (results) => {
      const json = JSON.stringify(results.data, null, 2);
      console.log(json);
      console.log(results.errors);
    }
  });
});

With header: true the parser uses the first row as keys and returns an array of objects. skipEmptyLines drops blank rows that would otherwise become empty objects. Always read results.errors: it reports rows with the wrong number of fields, which is the clearest sign of a damaged or misquoted file.

Why a library at all? Practitioners consistently point out that parsing CSV is not the same as calling split(',') on each line, because of embedded commas, line breaks inside quoted cells and escaped quotes. Papa Parse is built to handle those cases and is described by the Open Water Foundation’s CSV guide as an in-browser parser that copes with large files and malformed input.

You can try a snippet like this without installing anything in our in-browser JavaScript playground, which runs JS in the page.

In the browser with JavaScript — overview diagram

In Python with the standard library

For a one-off script with no dependencies, the csv module is enough. According to the Python documentation, csv.DictReader maps each row to a dictionary, and the result can be written out with json.dump:

import csv, json

with open("people.csv", newline="", encoding="utf-8") as f:
    rows = list(csv.DictReader(f))

with open("people.json", "w", encoding="utf-8") as f:
    json.dump(rows, f, indent=2, ensure_ascii=False)

Note the newline="" argument. The same documentation advises opening CSV files this way so the module can correctly handle line endings (CRLF versus LF), which matters when quoted fields contain line breaks. Skipping it can corrupt such records.

As with the browser approach, every value in rows is a string. To convert selected columns, loop over rows and cast them yourself, for example row["id"] = int(row["id"]), wrapped in handling for blanks.

In Python with pandas

For larger datasets or files you want to filter and reshape, pandas is the common choice. The research behind this guide points to its to_json(orient='records') method as the efficient route:

import pandas as pd

df = pd.read_csv("people.csv", dtype={"id": str})
df.to_json("people.json", orient="records", indent=2)

The dtype argument keeps id as text. Without it, pandas infers types per column, so a column of 001, 002 would become numbers. Empty cells in numeric columns become NaN in pandas and are written as null in JSON, which is worth knowing if downstream code expects empty strings.

Which method to pick

Situation Good fit
One file, sensitive data, no coding wanted A local, in-browser converter
Building a web page that accepts CSV uploads Papa Parse in the page
Repeatable script, no dependencies csv.DictReader plus json.dump
Big file, filtering or type control needed pandas

The edge cases that corrupt data

Most bad conversions come from the same short list of problems.

Six common CSV conversion pitfalls

Quoted fields. The format’s closest thing to a standard is RFC 4180, which notes that CSV was never formally documented and defines double quotes around fields that contain commas, line breaks or quotes. Erratum 5345 argues those fields must be quoted, not merely should be. In practice, a quote inside a quoted cell is escaped by doubling it ("He said ""hi"""). A parser that follows the RFC handles this; a hand-rolled splitter does not.

Other delimiters. Many European exports use semicolons because the comma is the decimal separator. Others use tabs. If your JSON comes out with a single giant key, the delimiter is almost certainly wrong. Set it explicitly instead of relying on detection.

Decimal formats. A cell such as 1.234,56 is text in a locale convention, not a JSON number. Normalize it before conversion or convert it in code.

Byte order marks and encoding. Files saved from some spreadsheet programs may start with an invisible BOM, which can attach itself to the first header name (so the key looks like id but is not equal to "id"). Reading with UTF-8 and checking the first key is a quick test.

Ragged rows. A row with fewer or more fields than the header is a symptom, usually of an unclosed quote earlier in the file. Fix the source rather than trusting the parser’s guess.

Duplicate headers. As noted above, the later column silently overwrites the earlier one in many implementations, so values vanish without an error.

Step 4: Check the result

A conversion that ran without errors is not necessarily a correct one. A few quick checks take a minute.

  1. Count. The number of objects should equal the number of CSV data rows (not counting the header or deliberately skipped blank lines).
  2. Spot-check the awkward rows. Find the row with quotes, a line break or a comma in a cell and read its JSON.
  3. Check the first and last keys. A BOM shows up on the first, a stray footer on the last.
  4. Read the formatted output. Paste the JSON into a formatter to confirm it is valid and to see the structure. GizmoBench’s JSON Formatter sits with our other developer utilities and runs in the browser.
  5. Infer and enforce a schema. If this conversion will recur, generate a draft with a JSON Schema generator that infers from sample JSON, tighten it by hand (for example, mark id as required and a string), then run each new file through a JSON Schema validator with error paths. Rows that violate the schema are reported with their location, so you find the broken record instead of the broken pipeline.

If the output is large and you would rather have one record per line (a format often called JSON Lines or NDJSON), you can inspect it with a JSONL viewer that shows records and errors.

Going the other direction, and using the JSON

Round trips are a useful test. If you flatten your JSON back into a table and the columns match the original CSV, the structure survived. Our JSON to CSV converter handles nested keys and lets you choose columns, which helps when the JSON has grown more complex than the original sheet. If you are writing a typed application, a JSON to TypeScript and Dart generator can turn a sample record into model definitions, which is where the type decisions from Step 2 pay off.

Other structured sources follow the same logic. An XML to CSV converter can bring XML data into a table first, and contact lists can move between formats with the CSV and vCard converter.

A browser-first approach to your data

GizmoBench is a collection of free browser tools for everyday and technical tasks, and the tools run locally, with no account and no installation. File processing happens in your browser, so the files you work with are not sent to a server. The utilities in this tutorial’s workflow, including formatting, schema checking and conversion between data formats, are listed on our developer tools page, and the wider catalog is on the GizmoBench home page. Core tool functions need no account, though we do not promise that every feature will stay free indefinitely.

Worked example: from messy export to clean JSON

Suppose a store exports orders with these rows (our own invented sample, for illustration only):

Order ID,Customer,Total,Notes
00417,"Rivera, Sam","1,250.00","Gift wrap ""please"""
00418,Okafor Lee,89.50,

Applying the steps in order:

  1. Clean. Rename headers to order_id, customer, total, notes. No title rows, no totals row, so nothing to delete.
  2. Decide. order_id stays a string to preserve 00417. total should become a number, but 1,250.00 contains a thousands separator, so strip the comma before casting.
  3. Convert. Parse with a real parser using the header row. The quoted comma in Rivera, Sam stays intact and the doubled quotes in the note become single quotes in the string value.
  4. Post-process. Cast total with a function that removes commas, and turn empty notes into null if your application prefers that.
  5. Check. Two data rows in, two objects out. The first object has "order_id": "00417", "total": 1250 and a note containing literal quotation marks.

The expected result:

[
  { "order_id": "00417", "customer": "Rivera, Sam", "total": 1250, "notes": "Gift wrap \"please\"" },
  { "order_id": "00418", "customer": "Okafor Lee", "total": 89.5, "notes": null }
]

The number 1250 shows no trailing zeros because JSON numbers do not preserve them. If you need to show two decimal places, format the value when you display it rather than storing it as text.

Limits worth knowing

  • File size. Browser conversion uses your device’s memory. Very large files (hundreds of megabytes) may need streaming in a script or a database import instead.
  • Nested data. CSV is flat. Converting it produces flat objects. If you want nested JSON (an address object, say), you have to reshape it after parsing, for example by splitting address.city style headers in code.
  • Ambiguity is yours to resolve. No converter can know whether 1/2/26 is January 2 or February 1, or whether an empty cell means zero or unknown. Document your rules.
  • Our own assumptions. The examples here are illustrative samples and the type-handling advice is general practice, not a measured benchmark. Test with a copy of your own data before relying on any pipeline.

FAQ

What is the simplest way to convert CSV to JSON?

For a single file, paste or load it into a local converter that parses with a real CSV library and uses the first row as keys. For repeated work, a short Python script with csv.DictReader and json.dump needs no extra packages. Either way, spot-check rows that contain commas or quotes.

Why are all my numbers strings in the JSON?

CSV stores only text, so parsers return strings unless you ask them to guess types or convert columns yourself. That default protects values such as ZIP codes and IDs with leading zeros. Convert only the columns you know are numeric.

Can I parse a CSV file in the browser without uploading it?

Yes. A page can read a local file with the browser’s FileReader and pass it to a parser such as Papa Parse, so the contents stay on your device. This is the approach GizmoBench tools take for file processing.

Why does my converted JSON have one key containing everything?

The delimiter probably is not a comma. Semicolon- and tab-separated files are common, and a parser using the wrong delimiter reads each line as one field. Set the delimiter explicitly and convert again.

Should I use an array of objects or an array of arrays?

Use an array of objects in most cases, since field names travel with every record and the data is self-describing. Arrays of arrays are more compact but depend on column order, which makes them easier to misread.

Sources