How to Convert CSV to JSON From the Terminal (csvkit, Miller, Python, and the Edge-Case Rule)
CodexFuse Team · 2026-11-04T07:34:55.213Z · 13 min read min read
Learning how to convert CSV to JSON from the terminal is one of those small skills that pays off constantly: data exports arrive as CSV, but APIs, configs, and JavaScript all want JSON. For a one-off file, CodexFuse's CSV to JSON tool does it in your browser — but the moment the conversion becomes a repeated step in a script or a data pipeline, you want a command you can run, re-run, and automate. This guide gives you three tested ways to do it from the command line: csvjson from csvkit, Miller's mlr, and a Python one-liner that needs no installation at all.
Every command below was run and verified on 4 November 2026 against csvkit 2.2.0, Miller 6.22.0, and Python 3.12.3, using a test CSV with deliberately nasty cells: an embedded comma (New York, NY), doubled quotes (Dan "The Hammer" Cole), and a newline inside a field. That test file is the point of this guide — converting a clean three-column CSV is trivial; the interesting question is what happens when the data is real.
What is the fastest way to convert CSV to JSON in the terminal?
The fastest csv to JSON command line approach is a one-liner with a real CSV parser — not awk, not cut, not string splitting. All three commands below read the same tricky.csv and print a JSON array of objects:
- csvkit:
csvjson tricky.csv > tricky.json - Miller:
mlr --c2j cat tricky.csv > tricky.json - Python:
cat tricky.csv | python3 -c 'import csv, json, sys; print(json.dumps(list(csv.DictReader(sys.stdin))))' > tricky.json
Pick any one and you have working JSON. The rest of this guide explains when each one wins, how to handle delimiters, encodings, and giant files, and the one rule that decides whether your conversion silently corrupts data.
How do I convert CSV to JSON with csvkit's csvjson?
csvjson is part of csvkit, a Python suite of command-line tools built specifically for working with CSV (the project has 6,418 GitHub stars as of 4 November 2026). Its own --help text describes it plainly: "Convert a CSV file into JSON (or GeoJSON)." If the terminal itself is new territory for you, our Git beginner guide is a gentle on-ramp to command-line basics before you start installing tools.
If you searched for "csvjson csvkit", you are in the right place: csvjson is the conversion subcommand inside the csvkit suite. Install it with the command from the official docs:
pip install csvkit
(Homebrew users get brew install csvkit as the documented alternative.) The simplest conversion is:
csvjson data.csv > data.json
Two things to know about the default output, both verified by testing version 2.2.0. First, csvjson emits a JSON array of objects, using the header row as the keys. Second, the output is compact — everything on one line. Pretty-printing is opt-in, and the --help text says so outright: -i INDENT, --indent INDENT, "Indent the output JSON this many spaces. Disabled by default." So for readable output:
csvjson -i 2 data.csv > data.json
csvjson also reads from a pipe — the help text says FILE "will accept input as piped data via STDIN" when omitted — so it slots into pipelines:
cat data.csv | csvjson > data.json
The csvjson flags you will actually use
-d ';' sets the delimiter for semicolon-separated exports (tested working on a ;-delimited file), and -t is the shortcut for tab-delimited input. -H handles files with no header row by inventing default headers (a, b, c, ...) — but note that the first line then becomes data, so only use it when the file genuinely has no headers. -k name changes the output shape entirely: instead of an array, you get an object keyed by a column, tested here as {"O'Brien, Pat": {"name": "O'Brien, Pat", ...}, ...} — handy for building lookup tables.
The type-inference surprise
Here is the quirk to know before it bites you: by default csvjson infers types, and its inference turns integers into floats. Tested in 2.2.0, a row of 1,apple,2.5 came out as {"id": 1.0, "name": "apple", "price": 2.5} — the 1 became 1.0. If your downstream system distinguishes ints from floats, disable inference with -I (everything stays a string). One more honest note from testing: the -l line-numbers flag is accepted but produced byte-identical output to the default in 2.2.0 — treat it as a no-op and do not rely on it.
How do I convert CSV to JSON with Miller?
Miller (mlr) describes itself on GitHub as "like awk, sed, cut, join, and sort for name-indexed data such as CSV, TSV, and tabular JSON" — 10,055 stars as of 4 November 2026 — and the current release is 6.22.0. It converts and transforms: conversion flags chain with Miller's verbs, so mlr --c2j sort -nr av_rating ./tv_ratings.csv sorts and converts in one pass.
Install it through your package manager — the GitHub README documents apt-get install miller, brew install miller, and choco install miller. One gotcha verified this run: pip install miller installs an unrelated PyPI package (version 0.2.3, "Introspection tools" by a different author) that does not provide the mlr command. Get the real binary from your package manager or the GitHub releases page.
The conversion itself:
mlr --c2j cat tricky.csv > tricky.json
If you searched for "miller csv to json", the flag to learn is --c2j — the documented CSV-to-JSON shortcut (the long form is --icsv --ojson), and cat is Miller's pass-through verb. Article-critical detail, settled by the official docs plus a local test: Miller wraps the output in a [ ] array by default. The docs say it verbatim — "--jlistwrap … This is the default for JSON output format" — and the test confirmed a pretty-printed array, one key-value pair per line. Several third-party tutorials claim otherwise; they are describing older behavior or confusing it with JSON Lines.
Miller's type inference is more careful than csvkit's: tested, "1" became int 1, "2.5" became float 2.5, and "02139" stayed the string "02139" — the leading zero is preserved instead of being mangled into a number. Custom delimiters use --ifs:
mlr --c2j --ifs ';' cat data.csv > data.json
How do I convert CSV to JSON with a Python one-liner?
Python's standard library needs no installation, which makes this the portable choice — it works on any machine with Python 3. The two pieces are csv.DictReader, which the Python docs describe as mapping "the information in each row to a dict whose keys are given by … the values in the first row," and json.dumps, which the docs define as "Serialize obj to a JSON formatted str." This python csv to json one liner works anywhere Python 3 exists — tested verbatim:
cat tricky.csv | python3 -c 'import csv, json, sys; print(json.dumps(list(csv.DictReader(sys.stdin))))'
That prints a compact JSON array — json.dumps inserts no newlines by default. For a readable version, pass indent=2. If you prefer reading a file by name instead of a pipe, this tested variant is equivalent:
python3 -c 'import csv, json, sys; f=open(sys.argv[1], newline=""); print(json.dumps(list(csv.DictReader(f))))' tricky.csv
Two details from the Python docs matter for real files. First, when opening a CSV file object, it "should be opened with newline=''" — the csv module handles line endings itself, and letting the OS translate them first breaks fields that contain embedded newlines. Second, Python does no type inference: every value comes out a string ("30", not 30), which is predictable and safe — convert types explicitly if you need them. Encodings: open() decodes as UTF-8 by default; pass encoding= for anything else.
Which tool should I use: csvjson, Miller, or Python?
There is no universal winner — each tool has a lane where it is clearly the best choice. The table below summarizes the tested behavior; read it as a decision aid, not a ranking.
| csvjson (csvkit) | mlr (Miller) | Python one-liner | |
|---|---|---|---|
| Install | pip install csvkit | Package manager or GitHub release (NOT pip) | None — standard library |
| Basic command | csvjson data.csv | mlr --c2j cat data.csv | python3 -c 'import csv, json, sys; print(json.dumps(list(csv.DictReader(sys.stdin))))' |
| Default output | Compact JSON array | Pretty-printed JSON array | Compact JSON array |
| Type inference | Aggressive — 1 becomes 1.0; disable with -I | Careful — leading zeros stay strings | None — everything is a string |
| JSON Lines | --stream | --ojsonl (or --c2l) | Print one json.dumps(row) per row |
| Big files | --stream avoids building the whole array | Built for scale; --ojsonl streams | Iterate rows instead of list() |
| Transforms while converting | Minimal (-k re-keys) | Full verb language (sort, filter, reshape) | Full Python |
| Best when | You want the simplest correct command | You also need to clean or reshape the data | You can install nothing and want full control |
A practical rule of thumb: reach for csvjson for quick one-off conversions, Miller when the data needs surgery on the way through, and Python when you are already scripting and want zero new dependencies.
What is the difference between a JSON array and JSON Lines?
Cluster members on this page include "csv to json lines", so this deserves its own answer. A JSON array is one document: [{...}, {...}]. A tool reading it must hold the whole thing in memory. JSON Lines (also called NDJSON) puts one complete JSON object per line, with no wrapping array — each line is independently parseable, so a pipeline can process a million rows without ever loading them all.
All three tools do both. In csvkit, --stream means "Output JSON as a stream of newline-separated objects, rather than an as an array" (help text verbatim; tested: one compact object per line). In Miller, --ojsonl selects "JSON Lines format for output data" (tested), and --c2l is the keystroke-saving equivalent. One subtlety from testing: Miller's --no-jlistwrap alone does not give you JSON Lines — objects stay multi-line pretty-printed because Miller's other default, --jvstack, puts one key-value pair per line. Use --ojsonl when you mean JSON Lines. In Python, print one json.dumps(row) per row instead of building a list (both forms tested this run).
Choose JSON Lines when the output feeds a streaming pipeline — log ingestion, jq -c filters, anything row-by-row. Choose the array when a human or an API expects one complete document.
What is the edge-case rule for CSV files?
The edge-case rule is the whole reason this guide recommends parsers instead of text tricks: never parse CSV by splitting on commas. CSV has quoting rules, and real-world exports use them constantly. RFC 4180 — the format's defining document, published October 2005 — states the two rules that break naive parsing. Rule 6: "Fields containing line breaks (CRLF), double quotes, and commas should be enclosed in double-quotes." Rule 7: "If double-quotes are used to enclose fields, then a double-quote appearing inside a field must be escaped by preceding it with another double quote."
Here is what happens when you ignore those rules, tested this run. Feeding the tricky CSV through jq's raw-input split — a command a surprising number of tutorials suggest — produced this mangling:
["\"Alice\"", "\"30\"", "\"New York", " NY\""]
The quoted "New York, NY" split into four columns, and the doubled quotes in Dan "The Hammer" Cole came out garbled. The same file through csvjson, Miller, or the Python one-liner parsed every tricky cell correctly — embedded comma, doubled quotes, and the embedded newline all survived, because those tools implement the quoting rules instead of pretending commas are sacred.
This is also where jq's role becomes clear: jq is a JSON processor, not a CSV parser. Convert with one of the three tools above, then use jq on the result — that division of labor is the correct one.
How do I check that the output is valid JSON?
Before piping converted data anywhere important, validate it. Both checks below were run this run:
csvjson data.csv | python3 -m json.tool > /dev/null && echo OK
mlr --c2j cat data.csv | jq -e . > /dev/null && echo OK
python3 -m json.tool parses and re-serializes; jq -e . exits non-zero on invalid input. Either one turns "is this actually JSON?" into a scriptable yes/no — wire it into your pipeline right after the conversion step and you will catch corrupt exports before they travel further downstream.
Sources
- csvkit documentation, "1.2. Installing csvkit" (csvkit 2.2.0) —
pip install csvkitinstall command: https://csvkit.readthedocs.io/en/latest/tutorial/1_getting_started.html csvjson --help(csvkit 2.2.0, installed and tested 2026-11-04) — default compact array output,--indent, STDIN behavior,--stream,-d,-H,-I,-k: installed package- Miller documentation, command-line flag list (6.22.0) —
--c2j,--jlistwrapdefault,--ojsonl,--c2l: https://miller.readthedocs.io/en/latest/reference-main-flag-list/ - Miller on GitHub — "like awk, sed, cut, join, and sort for name-indexed data", 10,055 stars (fetched 2026-11-04): https://github.com/johnkerl/miller
- csvkit on GitHub — 6,418 stars, MIT license (fetched 2026-11-04): https://github.com/wireservice/csvkit
- Python
csvmodule documentation —DictReaderbehavior,newline=''requirement, UTF-8 default encoding: https://docs.python.org/3/library/csv.html - Python
jsonmodule documentation —json.dumps, "Serializeobjto a JSON formattedstr": https://docs.python.org/3/library/json.html - RFC 4180 (October 2005) — quoting rules 6 and 7, header-line rule 3: https://www.rfc-editor.org/rfc/rfc4180.txt
Frequently Asked Questions
Can I use jq to convert CSV to JSON?
Not reliably. jq is a JSON processor — it has no CSV parser. The common jq -R split-on-commas trick breaks on the exact cells real CSVs contain: tested this run, a quoted "New York, NY" split into four columns and doubled quotes came out garbled. Convert with csvjson, Miller, or Python first, then use jq to query the JSON result.
Why did csvjson turn my integers into 1.0?
Type inference. csvjson infers column types by default, and its inference represents integers as floats — tested, 1 became 1.0. Pass -I (--no-inference) to keep every value a string, or post-process types in Python where you control the conversion explicitly.
How do I convert a semicolon-delimited CSV to JSON?
With csvkit: csvjson -d ';' data.csv (the -t flag is the tab shortcut). With Miller: mlr --c2j --ifs ';' cat data.csv. Both were tested on a semicolon-delimited file this run and parsed it correctly. Python's csv.DictReader takes a delimiter=';' argument for the same job.
Which option handles very large CSV files best?
Use a streaming form so the whole file is never held in memory: csvjson --stream, mlr --icsv --ojsonl cat big.csv, or in Python, iterate csv.DictReader and print one json.dumps(row) per row instead of building a list() — all tested this run. If the conversion runs as a recurring job on a server rather than your laptop, VPS hosting gives that pipeline a permanent home.
Do I need to install anything to convert CSV to JSON?
No — if Python 3 is available, the csv.DictReader + json.dumps one-liner needs zero new packages. For csvjson, run pip install csvkit. For Miller, use your OS package manager or the GitHub releases page — and remember that pip install miller installs an unrelated package that does not provide the mlr command.
My data is in Excel, not CSV — now what?
Export the sheet to CSV from Excel (or LibreOffice) and follow this guide, or skip the export entirely with our Excel to JSON converter, which reads .xlsx and .xls files directly in your browser and offers the same array-of-objects or array-of-arrays shapes.

