Skip to content

How to convert CSV to JSON across languages

Real snippets to convert header-based CSV into JSON across languages. Includes dependencies when CSV parsing is not available in the standard library.

← Developer Zone
Updated: 2026-03-23

Use this article when...

This section is built for speed: one concrete task, multiple stacks, and the minimum context needed not to copy the wrong thing.

Use this after capturing the real payload

Work from the request or response body that actually failed instead of rebuilding JSON from memory.

Pick the language that matches the incident

The useful path here is fast adaptation: choose your stack, then copy only after reading the notes around parsing and formatting.

Validate the result with the tool

Once the snippet runs, inspect the live payload with JSON Formatter or the related tool to confirm the structure is really fixed.

What this article gives you

A short path from incident to implementation: context, language-specific snippets, and the warning signs that usually get skipped.

Languages

13

Related tools

3

Topics

csv, json, data, conversion, imports

CSV is still common for exports, quick migrations, and handoff to non-technical teams. The problem starts when you need to inspect records, validate columns, or turn that data into payloads your scripts and APIs can actually use.

Converting CSV to JSON is not just a format swap. It makes row shape, empty values, duplicate headers, and typing assumptions visible before they break an import.

Dependency snapshot by language

Check this first to see which snippets use built-in/runtime APIs and which ones need external packages before you start copying code.

Bash
Built-in

Built-in or runtime API

C#
External

CsvHelper.

Delphi
Built-in

Built-in or runtime API

Go
Built-in

Built-in or runtime API

Java
Check notes

Review the notes for setup details.

JavaScript
External

csv-parse.

Kotlin
Check notes

Review the notes for setup details.

PHP
Built-in

Built-in or runtime API

Python
Built-in

Built-in or runtime API

Ruby
Built-in

Built-in or runtime API

Rust
Check notes

Review the notes for setup details.

TypeScript
External

csv-parse.

VB.NET
Built-in

Built-in or runtime API

How to use these code examples well

The snippet is only the fast path. The explanation and notes are what keep you from copying the wrong assumption into production.

1. Start with the problem

Make sure the article really matches the issue you are debugging before copying code just because the title looks close.

2. Read the notes

That is where portability limits, dependency requirements, and runtime assumptions usually appear.

3. Validate the output

If the code runs but the bug remains, jump to the related tool and inspect the real payload, token, timestamp, or config.

Code examples by language

Snippets that compile/run, plus short explanations and real-world notes.

Bash

bash
Bash
python3 - <<'PY'
import csv
import json
from io import StringIO

csv_text = """id,name,active
1,Ana,true
2,Luis,false
"""

rows = list(csv.DictReader(StringIO(csv_text)))
print(json.dumps(rows, indent=2, ensure_ascii=False))
PY
Explanation

If Python is already available, this is a practical terminal path: DictReader uses the first row as headers and json.dumps produces readable output.

Notes
  • Uses only the standard library.
  • Values remain strings unless you add type inference afterwards.

C#

csharp
C#
using System.Globalization;
using System.Linq;
using System.Text.Json;
using CsvHelper;
using CsvHelper.Configuration;

var csvText = """
id,name,active
1,Ana,true
2,Luis,false
""";

using var textReader = new StringReader(csvText);
using var csv = new CsvReader(textReader, new CsvConfiguration(CultureInfo.InvariantCulture));
var rows = csv.GetRecords<dynamic>().ToList();
Console.WriteLine(JsonSerializer.Serialize(rows, new JsonSerializerOptions { WriteIndented = true }));
Explanation

CsvHelper handles CSV parsing robustly and lets you serialize the result directly to JSON with System.Text.Json.

Notes
  • Dependency: CsvHelper.
  • Good fit for import jobs and internal .NET utilities.

Delphi

delphi
Delphi
program CsvToJson;

{$APPTYPE CONSOLE}

uses
  System.SysUtils,
  System.Classes,
  System.JSON;

function ParseLine(const Line: string): TStringList;
begin
  Result := TStringList.Create;
  Result.StrictDelimiter := True;
  Result.Delimiter := ',';
  Result.DelimitedText := Line;
end;

var
  Lines, Headers, Values: TStringList;
  JsonRows: TJSONArray;
  JsonRow: TJSONObject;
  I, J: Integer;

begin
  Lines := TStringList.Create;
  JsonRows := TJSONArray.Create;
  try
    Lines.Text := 'id,name,active' + sLineBreak + '1,Ana,true' + sLineBreak + '2,Luis,false';
    Headers := ParseLine(Lines[0]);
    try
      for I := 1 to Lines.Count - 1 do
      begin
        Values := ParseLine(Lines[I]);
        try
          JsonRow := TJSONObject.Create;
          for J := 0 to Headers.Count - 1 do
            JsonRow.AddPair(Headers[J], Values[J]);
          JsonRows.AddElement(JsonRow);
        finally
          Values.Free;
        end;
      end;
      Writeln(JsonRows.Format(2));
    finally
      Headers.Free;
    end;
  finally
    JsonRows.Free;
    Lines.Free;
  end;
end.
Explanation

In Delphi you can handle simple CSV with TStringList.DelimitedText and build the final JSON using System.JSON without external dependencies.

Notes
  • Standard library only.
  • Good for simple CSV; if you need multiline fields or harder edge cases, use a dedicated CSV parser.

Go

go
Go
package main

import (
  "encoding/csv"
  "encoding/json"
  "fmt"
  "strings"
)

func main() {
  input := "id,name,active
1,Ana,true
2,Luis,false
"

  reader := csv.NewReader(strings.NewReader(input))
  records, err := reader.ReadAll()
  if err != nil {
    panic(err)
  }

  headers := records[0]
  rows := make([]map[string]string, 0, len(records)-1)
  for _, record := range records[1:] {
    row := make(map[string]string, len(headers))
    for index, header := range headers {
      row[header] = record[index]
    }
    rows = append(rows, row)
  }

  out, _ := json.MarshalIndent(rows, "", "  ")
  fmt.Println(string(out))
}
Explanation

encoding/csv and encoding/json cover the usual case with no external dependencies. Enough for CLIs and simple operational transforms.

Notes
  • Standard library only.
  • If columns may be missing or extra, validate field counts before indexing rows.

Java

java
Java
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.MappingIterator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
import java.util.Map;

public class Main {
  public static void main(String[] args) throws Exception {
    String input = """
      id,name,active
      1,Ana,true
      2,Luis,false
      """;

    CsvMapper csvMapper = new CsvMapper();
    CsvSchema schema = CsvSchema.emptySchema().withHeader();
    MappingIterator<Map<String, String>> rows =
        csvMapper.readerFor(new TypeReference<Map<String, String>>() {}).with(schema).readValues(input);

    ObjectMapper jsonMapper = new ObjectMapper();
    System.out.println(jsonMapper.writerWithDefaultPrettyPrinter().writeValueAsString(rows.readAll()));
  }
}
Explanation

Jackson CSV lets you parse the header and obtain rows as maps without maintaining a manual parser in Java.

Notes
  • Dependencies: jackson-databind and jackson-dataformat-csv.
  • Useful when CSV is already part of a backend pipeline in Java.

JavaScript

javascript
JavaScript
import { parse } from 'csv-parse/sync';

const input = [
  'id,name,active',
  '1,Ana,true',
  '2,Luis,false'
].join('
');

const rows = parse(input, {
  columns: true,
  skip_empty_lines: true
});

console.log(JSON.stringify(rows, null, 2));
Explanation

In Node.js it is better to rely on a real CSV parser. csv-parse handles quotes, embedded commas, and common edge cases much better than manual splitting.

Notes
  • Dependency: csv-parse.
  • columns: true uses the first row as headers automatically.

Kotlin

kotlin
Kotlin
import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.dataformat.csv.CsvMapper
import com.fasterxml.jackson.dataformat.csv.CsvSchema
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper

fun main() {
  val input = """
    id,name,active
    1,Ana,true
    2,Luis,false
  """.trimIndent()

  val csvMapper = CsvMapper()
  val schema = CsvSchema.emptySchema().withHeader()
  val rows = csvMapper
    .readerFor(object : TypeReference<Map<String, String>>() {})
    .with(schema)
    .readValues<Map<String, String>>(input)
    .readAll()

  println(jacksonObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(rows))
}
Explanation

In Kotlin/JVM you can reuse Jackson CSV just like in Java and still produce readable JSON with very little extra code.

Notes
  • Dependencies: jackson-dataformat-csv and jackson-module-kotlin.
  • A good option for internal JVM tooling.

PHP

php
PHP
<?php
$csv = <<<CSV
id,name,active
1,Ana,true
2,Luis,false
CSV;

$handle = fopen('php://temp', 'r+');
fwrite($handle, $csv);
rewind($handle);

$headers = fgetcsv($handle);
$rows = [];

while (($values = fgetcsv($handle)) !== false) {
    $rows[] = array_combine($headers, $values);
}

fclose($handle);

echo json_encode($rows, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . PHP_EOL;
Explanation

fgetcsv already solves CSV parsing so you do not have to invent your own parser. Using a temporary stream lets you reuse the native API even when the CSV arrives as a string.

Notes
  • Standard functions only.
  • array_combine assumes each row has the same number of columns as the header.

Python

python
Python
import csv
import json
from io import StringIO

csv_text = """id,name,active
1,Ana,true
2,Luis,false
"""

reader = csv.DictReader(StringIO(csv_text))
rows = list(reader)
print(json.dumps(rows, indent=2, ensure_ascii=False))
Explanation

csv.DictReader is probably the most direct way in Python to convert header-based rows into JSON objects.

Notes
  • Standard library only.
  • As in many stacks, type inference is still your decision after parsing.

Ruby

ruby
Ruby
require 'csv'
require 'json'

csv_text = <<~CSV
  id,name,active
  1,Ana,true
  2,Luis,false
CSV

rows = CSV.parse(csv_text, headers: true).map(&:to_h)
puts JSON.pretty_generate(rows)
Explanation

Ruby ships with CSV and JSON in the standard library, so you can move from export to readable objects with very little code.

Notes
  • Standard library only.
  • headers: true maps each row to a hash using the first line.

Rust

rust
Rust
use csv::ReaderBuilder;
use serde_json::{Map, Value};

fn main() {
    let input = "id,name,active
1,Ana,true
2,Luis,false
";
    let mut reader = ReaderBuilder::new().from_reader(input.as_bytes());
    let headers = reader.headers().unwrap().clone();

    let rows: Vec<Value> = reader
        .records()
        .map(|record| {
            let record = record.unwrap();
            let mut object = Map::new();
            for (header, value) in headers.iter().zip(record.iter()) {
                object.insert(header.to_string(), Value::String(value.to_string()));
            }
            Value::Object(object)
        })
        .collect();

    println!("{}", serde_json::to_string_pretty(&rows).unwrap());
}
Explanation

The csv crate handles parsing and serde_json lets you build a clean JSON output for inspection or handoff.

Notes
  • Dependencies: csv = "1", serde_json = "1".
  • If you want type inference, do it before inserting values into the JSON.

TypeScript

ts
TypeScript
import { parse } from 'csv-parse/sync';

const input = [
  'id,name,active',
  '1,Ana,true',
  '2,Luis,false'
].join('
');

const rows = parse(input, {
  columns: true,
  skip_empty_lines: true
}) as Array<Record<string, string>>;

console.log(JSON.stringify(rows, null, 2));
Explanation

The TypeScript pattern is almost identical to Node.js, but with explicit typing to make the row shape clear.

Notes
  • Dependency: csv-parse.
  • If you normalize types afterwards, type the final result against your real contract.

VB.NET

vbnet
VB.NET
Imports System
Imports System.Collections.Generic
Imports System.IO
Imports System.Text.Json
Imports Microsoft.VisualBasic.FileIO

Module Program
  Sub Main()
    Dim csvText = "id,name,active" & Environment.NewLine &
                  "1,Ana,true" & Environment.NewLine &
                  "2,Luis,false"
    Dim rows As New List(Of Dictionary(Of String, String))()

    Using parser As New TextFieldParser(New StringReader(csvText))
      parser.TextFieldType = FieldType.Delimited
      parser.SetDelimiters(",")

      Dim headers = parser.ReadFields()
      While Not parser.EndOfData
        Dim fields = parser.ReadFields()
        Dim row As New Dictionary(Of String, String)()
        For i = 0 To headers.Length - 1
          row(headers(i)) = fields(i)
        Next
        rows.Add(row)
      End While
    End Using

    Console.WriteLine(JsonSerializer.Serialize(rows, New JsonSerializerOptions With {.WriteIndented = True}))
  End Sub
End Module
Explanation

TextFieldParser handles delimited CSV in VB.NET and lets you turn each row into a dictionary before serializing it to JSON with System.Text.Json.

Notes
  • Only the .NET/VB runtime.
  • Usually handles quotes and delimiters better than manual splitting.

Related tools

Use the tool when you need to generate or validate output fast.

Trust and privacy

Copy/paste-friendly by design. Still, treat real production secrets carefully.

  • Prefer synthetic examples when sharing screens or recording.
  • Do not paste real API keys, tokens, or personal data unless you fully trust your environment.
  • If you need ordering, do not use UUID v4 as a sortable id: add createdAt or use sortable ids.