CSV to JSON JavaScript — Converter + Code Examples

·Front-end & Node.js Developer·Révisé parSophie Laurent·Publié

Utilisez le CSV vers JSON gratuit directement dans votre navigateur — sans installation.

Essayer CSV vers JSON en ligne →

La plupart des données CSV que je rencontre arrivent sous forme de chaîne plate depuis un upload de fichier, un export de base de données, ou une API qui parle encore le format des années 1970. Pour convertir du CSV en JSON en JavaScript, tu as besoin de deux choses que le langage te offre gratuitement : le découpage de chaînes pour analyser les lignes et JSON.stringify() pour sérialiser le résultat. Aucun package npm requis pour les bases — ce guide couvre l\'intégralité du pipeline depuis un utilitaire csvToJson() réutilisable jusqu'à PapaParse et les entrées/sorties de fichiers Node.js. Pour des conversions rapides sans code, le convertisseur CSV vers JSON en ligne s'en charge instantanément. Tous les exemples ciblent Node.js 18+ et les navigateurs modernes.

  • Découpe le CSV par saut de ligne, extrait les en-têtes de la ligne 0, mappe les lignes restantes en objets, puis JSON.stringify(array, null, 2) pour une sortie formatée.
  • JSON.stringify() produit une chaîne ; JSON.parse() la reconvertit en tableau JavaScript vivant — sache lequel tu as avant d'opérer dessus.
  • Les instances Map ne se sérialisent pas automatiquement en JSON — appelle Object.fromEntries(map) d'abord.
  • Pour les CSV avec des champs entre guillemets, des virgules dans les valeurs ou des sauts de ligne dans les cellules, utilise PapaParse ou csv-parse plutôt que le découpage manuel.
  • csvtojson (npm) gère la coercition de types, le streaming et les cas limites RFC 4180 en un seul appel.

Qu'est-ce que la conversion CSV vers JSON ?

La conversion CSV vers JSON transforme un format texte plat délimité par des virgules en un tableau structuré d'objets où chaque ligne devient un objet JavaScript dont les clés viennent des en-têtes de colonnes. Le format CSV n'a pas de types de données — tout est une chaîne. JSON ajoute une structure, de l'imbrication et des types explicites (nombres, booléens, null). Cette conversion est la première étape de presque chaque pipeline de données qui commence par un export de tableur, un dump de système legacy ou un fichier uploadé par l'utilisateur. Les données sous-jacentes restent les mêmes ; le format passe de colonnes positionnelles à des propriétés nommées.

Before · json
After · json
name,email,role,active
Marie Dupont,mdupont@nexuslabs.io,Engineering Lead,true
Thomas Martin,tmartin@nexuslabs.io,Product Manager,true
[
  {
    "name": "Marie Dupont",
    "email": "mdupont@nexuslabs.io",
    "role": "Engineering Lead",
    "active": "true"
  },
  {
    "name": "Thomas Martin",
    "email": "tmartin@nexuslabs.io",
    "role": "Product Manager",
    "active": "true"
  }
]

csvToJson() — Construire une fonction de conversion réutilisable

Le pipeline complet CSV vers JSON en JavaScript se décompose en trois étapes : découper la chaîne CSV par saut de ligne pour obtenir les lignes, extraire les en-têtes de la première ligne avec split(','), puis mapper chaque ligne restante vers un objet JavaScript ordinaire dont les clés viennent des en-têtes et les valeurs des positions de colonnes correspondantes. L'appel final à JSON.stringify() convertit ce tableau d'objets en chaîne JSON. Voici une version minimale fonctionnelle :

JavaScript — csvToJson minimal
function csvToJson(csv) {
  const lines = csv.trim().split('\n')
  const headers = lines[0].split(',').map(h => h.trim())

  const rows = lines.slice(1)
    .filter(line => line.trim() !== '')
    .map(line => {
      const values = line.split(',')
      return Object.fromEntries(
        headers.map((header, i) => [header, values[i]?.trim()])
      )
    })

  return JSON.stringify(rows, null, 2)
}

const csv = `server,port,region,status
api-gateway,8080,eu-west-3,healthy
auth-service,8443,eu-west-1,degraded
payments-api,9090,ap-south-1,healthy`

console.log(csvToJson(csv))
// [
//   { "server": "api-gateway", "port": "8080", "region": "eu-west-3", "status": "healthy" },
//   { "server": "auth-service", "port": "8443", "region": "eu-west-1", "status": "degraded" },
//   { "server": "payments-api", "port": "9090", "region": "ap-south-1", "status": "healthy" }
// ]

Cette fonction gère les bases : les sauts de ligne en fin de chaîne, les lignes vides, les espaces autour des valeurs. Chaque champ CSV passe sous forme de chaîne. Remarque que port est "8080" (une chaîne), pas 8080 (un nombre). Si tu as besoin de types corrects dans la sortie JSON, tu dois les contraindre toi-même. Voici une version étendue avec détection de type :

JavaScript — csvToJson avec coercition de types
function coerceValue(val) {
  if (val === undefined || val === '') return null
  if (val === 'true') return true
  if (val === 'false') return false
  if (val === 'null') return null
  const num = Number(val)
  if (!isNaN(num) && val.trim() !== '') return num
  return val
}

function csvToJson(csv, { coerce = false } = {}) {
  const lines = csv.trim().split('\n')
  const headers = lines[0].split(',').map(h => h.trim())

  const rows = lines.slice(1)
    .filter(line => line.trim() !== '')
    .map(line => {
      const values = line.split(',')
      return Object.fromEntries(
        headers.map((header, i) => [
          header,
          coerce ? coerceValue(values[i]?.trim()) : values[i]?.trim()
        ])
      )
    })

  return JSON.stringify(rows, null, 2)
}

const csv = `endpoint,port,max_connections,debug
/api/v2/orders,8443,500,true
/api/v2/health,8080,100,false`

console.log(csvToJson(csv, { coerce: true }))
// [
//   { "endpoint": "/api/v2/orders", "port": 8443, "max_connections": 500, "debug": true },
//   { "endpoint": "/api/v2/health", "port": 8080, "max_connections": 100, "debug": false }
// ]

L'indicateur coerce est opt-in car la détection automatique de types peut se retourner contre toi — un champ comme un code postal ("75001") perd son zéro initial quand il est converti en nombre. Garde la coercition désactivée par défaut et active-la seulement quand tu contrôles le schéma. Petit rappel : JSON.stringify() accepte un troisième argument space pour l'indentation. Passe 2 pour deux espaces, 4 pour quatre, ou "\t" pour des tabulations. Omets-le entièrement pour une sortie compacte sur une seule ligne — utile quand tu envoies la chaîne JSON comme corps d'une requête API où les espaces gaspillent simplement de la bande passante.

Note :Une chaîne CSV brute n'est pas du JSON. Appeler JSON.parse() directement sur du texte CSV lève une SyntaxError. Tu dois d'abord convertir le CSV en objets JavaScript avec ta fonction csvToJson(), qui appelle en interne JSON.stringify() pour produire la chaîne JSON réelle.

Gérer les Maps, Dates et objets personnalisés issus de données CSV

Toute conversion CSV ne se termine pas avec un tableau plat d'objets ordinaires. Parfois tu dois construire une Map depuis des paires en-tête/valeur, analyser des chaînes de dates en objets Date, ou attacher des propriétés calculées avant la sérialisation. JavaScript a un comportement particulier qui piège les gens : les instances Map ne se sérialisent pas avec JSON.stringify(). Tu obtiens un objet vide. La solution est Object.fromEntries() pour convertir la Map en objet ordinaire avant de la sérialiser.

La raison pour laquelle Map se sérialise en {} est que JSON.stringify() itère sur les propriétés énumérables propres d'un objet. Une Map stocke ses entrées dans un slot interne, pas en tant que propriétés énumérables sur l'objet lui-même, donc le sérialiseur voit un objet sans clés. Le prototype Map manque également d'une méthode toJSON(), qui est le point d'accroche que JSON.stringify() appelle en premier sur toute valeur avant de décider comment la sérialiser. Si une valeur a toJSON(), la valeur de retour de la méthode est ce qui est sérialisé — pas l'objet lui-même. C'est pourquoi les objets Date se sérialisent correctement : Date.prototype.toJSON retourne une chaîne ISO 8601, donc JSON.stringify(new Date()) produit un horodatage entre guillemets plutôt qu'un objet vide. Comprendre ce point d'accroche te permet de définir le même comportement sur tes propres classes — comme montré dans l'exemple EmployeeRecord ci-dessous — pour contrôler exactement quels champs issus du CSV apparaissent dans la sortie JSON finale.

Convertir une Map en JSON

JavaScript — Map vers JSON via Object.fromEntries()
// Construire une Map depuis des paires en-tête→valeur CSV
const headers = ['server', 'port', 'region']
const values = ['payments-api', '9090', 'ap-south-1']
const rowMap = new Map(headers.map((h, i) => [h, values[i]]))

// Map ne se sérialise PAS directement
console.log(JSON.stringify(rowMap))
// "{}"  — objet vide, données perdues !

// Convertir en objet ordinaire d'abord
const rowObj = Object.fromEntries(rowMap)
console.log(JSON.stringify(rowObj, null, 2))
// {
//   "server": "payments-api",
//   "port": "9090",
//   "region": "ap-south-1"
// }

Chaînes de dates et toJSON()

Les champs de date CSV arrivent sous forme de chaînes. Si tu les analyses en objets Date durant le traitement, ces Dates se sérialisent correctement car Date dispose d'une méthode toJSON() intégrée qui retourne une chaîne ISO 8601. Tu peux aussi définir un toJSON() personnalisé sur tes propres classes pour contrôler quelles colonnes CSV apparaissent dans la sortie sérialisée — par exemple, en omettant les champs de suivi internes comme _rowIndex.

JavaScript — toJSON() pour la sérialisation personnalisée
class EmployeeRecord {
  constructor(csvRow) {
    this._rowIndex = csvRow._rowIndex  // interne, pas pour JSON
    this.employeeId = csvRow.employee_id
    this.name = csvRow.name
    this.hiredAt = new Date(csvRow.hired_date)
    this.salary = Number(csvRow.salary)
  }

  toJSON() {
    // N'exposer que les champs souhaités dans la sortie JSON
    return {
      employee_id: this.employeeId,
      name: this.name,
      hired_at: this.hiredAt,  // Date.toJSON() → chaîne ISO automatiquement
      salary: this.salary,
    }
  }
}

const csvRow = {
  _rowIndex: 42,
  employee_id: 'EMP-2847',
  name: 'Marie Dupont',
  hired_date: '2024-03-15',
  salary: '128000',
}

const record = new EmployeeRecord(csvRow)
console.log(JSON.stringify(record, null, 2))
// {
//   "employee_id": "EMP-2847",
//   "name": "Marie Dupont",
//   "hired_at": "2024-03-15T00:00:00.000Z",
//   "salary": 128000
// }
// Note : _rowIndex est exclu, salary est un nombre, la date est au format ISO

Reviver pour la désérialisation des dates

Après avoir écrit le JSON issu du CSV dans un fichier ou l'avoir envoyé sur le réseau, JSON.parse() te retourne des objets ordinaires — les objets Date redeviennent des chaînes. Utilise une fonction reviver pour reconvertir les chaînes ISO 8601 en objets Date lors de l'analyse :

JavaScript — reviver pour reconstruire les objets Date
const jsonString = '{"employee_id":"EMP-2847","name":"Marie Dupont","hired_at":"2024-03-15T00:00:00.000Z","salary":128000}'

const isoDatePattern = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/

const parsed = JSON.parse(jsonString, (key, value) => {
  if (typeof value === 'string' && isoDatePattern.test(value)) {
    return new Date(value)
  }
  return value
})

console.log(parsed.hired_at instanceof Date)  // true
console.log(parsed.hired_at.getFullYear())    // 2024
Attention :JSON.stringify() retourne undefined (pas une chaîne) pour les valeurs qui contiennent des fonctions, des Symbols ou des propriétés undefined. Si tes objets issus du CSV récupèrent accidentellement une valeur undefined d'une colonne manquante, cette propriété disparaît silencieusement de la sortie JSON. Utilise toujours null comme valeur par défaut pour les valeurs manquantes.

Référence des paramètres de JSON.stringify()

La signature de la fonction est JSON.stringify(value, replacer?, space?). Les arguments replacer et space sont tous deux optionnels — passe null pour le replacer quand tu as seulement besoin d'indentation.

Paramètre
Type
Défaut
Description
value
any
(requis)
La valeur JavaScript à sérialiser — objet, tableau, chaîne, nombre, booléen ou null
replacer
Function | Array | null
undefined
Filtre ou transforme les valeurs lors de la sérialisation. Un tableau liste les noms de propriétés autorisés ; une fonction reçoit les paires (key, value)
space
number | string
undefined
Indentation : nombre de 0 à 10 pour les espaces, chaîne (ex. "\t") pour un retrait personnalisé. Omis pour une sortie compacte sur une seule ligne

Paramètres de JSON.parse() :

Paramètre
Type
Défaut
Description
text
string
(requis)
La chaîne JSON à analyser — doit être un JSON valide, sinon une SyntaxError est levée
reviver
Function | undefined
undefined
Appelé pour chaque paire clé-valeur. La valeur retournée remplace l'originale ; retourner undefined supprime la propriété

JSON.parse() — Consommer la sortie JSON

Une fois que tu as une chaîne JSON depuis csvToJson(), l'étape suivante est généralement de la réanalyser en tableau JavaScript vivant pour filtrer, mapper ou alimenter une API. La différence entre une chaîne JSON (typeof === "string") et un objet JavaScript est importante. Tu ne peux pas appeler .filter() ni accéder à [0].name sur une chaîne — tu as besoin de JSON.parse() d'abord. Cet aller-retour (stringify puis parse) fonctionne aussi comme technique de validation : si ta conversion CSV produit quelque chose qui n'est pas du JSON valide, parse lèvera une erreur. L'argument optionnel reviver te permet de transformer chaque paire clé-valeur lors de l'analyse — utile pour restaurer des objets Date depuis des chaînes ISO ou renommer des clés sans passe supplémentaire.

JavaScript — analyser la sortie JSON et interroger les lignes
const csv = `endpoint,method,avg_latency_ms,error_rate
/api/v2/orders,POST,342,0.02
/api/v2/health,GET,12,0.00
/api/v2/payments,POST,890,0.15
/api/v2/users,GET,45,0.01`

// Étape 1 : convertir le CSV en chaîne JSON
const jsonString = csvToJson(csv, { coerce: true })

// Étape 2 : réanalyser en tableau JavaScript
const endpoints = JSON.parse(jsonString)

// Vérifier que c'est un tableau
console.log(Array.isArray(endpoints))  // true

// Filtrer les endpoints à latence élevée
const slow = endpoints.filter(ep => ep.avg_latency_ms > 200)
console.log(slow.map(ep => ep.endpoint))
// ["/api/v2/orders", "/api/v2/payments"]

// Déstructurer la première ligne
const [first, ...rest] = endpoints
console.log(first.endpoint)  // "/api/v2/orders"
console.log(rest.length)     // 3

Un wrapper sécurisé pour JSON.parse() est utile pour valider la sortie de conversion avant un traitement en aval. Si la conversion CSV produit du JSON malformé pour une raison quelconque (entrée tronquée, erreurs d'encodage), cela le capture sans faire planter le programme :

JavaScript — wrapper d'analyse sécurisé
function safeParse(jsonString) {
  try {
    return { data: JSON.parse(jsonString), error: null }
  } catch (err) {
    return { data: null, error: err.message }
  }
}

// Sortie valide
const result = safeParse(csvToJson(csv))
if (result.error) {
  console.error('La conversion CSV a produit du JSON invalide :', result.error)
} else {
  console.log(`${result.data.length} lignes analysées`)
}

// Passer du CSV brut à JSON.parse — cela échoue
const bad = safeParse('name,email\nMarie,mdupont@nexuslabs.io')
console.log(bad.error)  // "Unexpected token 'a', "name,email"... is not valid JSON"

Reviver pour le renommage de clés et la validation

La fonction reviver reçoit chaque paire clé-valeur lors de l'analyse, des propriétés les plus internes vers l'extérieur. Retourner undefined pour une clé la supprime entièrement du résultat ; retourner une valeur différente la remplace. Le reviver est utile pour renommer les en-têtes (camelCase vers snake_case), supprimer des champs internes, ou vérifier que les colonnes requises existent. Il est appelé avec la valeur racine en dernier (clé chaîne vide), ce qui est l'endroit où tu lèves une erreur si le résultat n'est pas un tableau.

JavaScript — reviver pour le renommage de clés et la validation de forme
const jsonString = csvToJson(`employeeId,firstName,hiredDate
EMP-2847,Marie,2024-03-15
EMP-3012,Thomas,2023-11-01`, { coerce: false })

const camelToSnake = str => str.replace(/[A-Z]/g, c => '_' + c.toLowerCase())

const employees = JSON.parse(jsonString, function(key, value) {
  // Valeur racine — valider la forme
  if (key === '') {
    if (!Array.isArray(value)) throw new Error('Expected JSON array from CSV')
    return value
  }
  // Renommer les clés d'en-tête camelCase en snake_case
  if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
    return Object.fromEntries(
      Object.entries(value).map(([k, v]) => [camelToSnake(k), v])
    )
  }
  return value
})

console.log(employees[0])
// { employee_id: 'EMP-2847', first_name: 'Marie', hired_date: '2024-03-15' }

Convertir du CSV depuis un fichier et une réponse API

Les deux endroits d'où proviennent réellement les données CSV en production : les fichiers sur disque et les réponses HTTP. Les deux scénarios nécessitent une gestion d'erreurs car l'entrée est externe et non contrôlée.

Lire un fichier CSV, convertir, écrire en JSON

Node.js 18+ — conversion de fichier
import { readFileSync, writeFileSync } from 'node:fs'

function csvToJsonFromFile(inputPath, outputPath) {
  let csvText
  try {
    csvText = readFileSync(inputPath, 'utf8')
  } catch (err) {
    throw new Error(`Échec de lecture de ${inputPath} : ${err.message}`)
  }

  const lines = csvText.trim().split('\n')
  if (lines.length < 2) {
    throw new Error(`${inputPath} n'a pas de lignes de données (seulement ${lines.length} ligne)`)
  }

  const headers = lines[0].split(',').map(h => h.trim())
  const rows = lines.slice(1)
    .filter(line => line.trim() !== '')
    .map(line => {
      const values = line.split(',')
      return Object.fromEntries(headers.map((h, i) => [h, values[i]?.trim()]))
    })

  const jsonOutput = JSON.stringify(rows, null, 2)
  writeFileSync(outputPath, jsonOutput, 'utf8')
  console.log(`${rows.length} lignes converties → ${outputPath}`)
  return rows
}

// Utilisation
const data = csvToJsonFromFile('inventory.csv', 'inventory.json')
console.log(data[0])
// { sku: "WDG-2847", warehouse: "eu-west-3", quantity: "150", ... }

Récupérer du CSV depuis un endpoint API

Node.js 18+ — conversion de réponse API
async function fetchCsvAsJson(url) {
  const response = await fetch(url)
  if (!response.ok) {
    throw new Error(`HTTP ${response.status} : ${response.statusText}`)
  }

  const contentType = response.headers.get('content-type') || ''
  if (!contentType.includes('text/csv') && !contentType.includes('text/plain')) {
    console.warn(`Content-type inattendu : ${contentType}`)
  }

  const csvText = await response.text()
  const lines = csvText.trim().split('\n')
  const headers = lines[0].split(',').map(h => h.trim())
  const rows = lines.slice(1)
    .filter(line => line.trim() !== '')
    .map(line => {
      const values = line.split(',')
      return Object.fromEntries(headers.map((h, i) => [h, values[i]?.trim()]))
    })

  return rows
}

// Exemple : récupérer un CSV de taux de change depuis un fournisseur de données
try {
  const rates = await fetchCsvAsJson('https://data.ecb.internal/rates/daily.csv')
  console.log(JSON.stringify(rates.slice(0, 3), null, 2))
  // Envoyer en JSON au service en aval
  await fetch('https://api.internal/v2/rates', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ data: rates }),
  })
} catch (err) {
  console.error('Synchronisation des taux échouée :', err.message)
}
Note :L'argument replacer dans JSON.stringify() te permet de lister les colonnes spécifiques du CSV à inclure. Passe un tableau de noms d'en-têtes pour inclure seulement ces champs : JSON.stringify(rows, ['name', 'email', 'department']). Les propriétés absentes du tableau sont silencieusement exclues de la sortie.

Conversion CSV vers JSON en ligne de commande

Node.js peut exécuter des scripts en ligne, et il existe des outils CLI dédiés qui gèrent la conversion CSV vers JSON sans écrire de script.

bash — script Node.js en une ligne
# Piper du CSV vers un script Node.js en ligne
cat servers.csv | node -e "
  const lines = require('fs').readFileSync('/dev/stdin','utf8').trim().split('\n');
  const h = lines[0].split(',');
  const rows = lines.slice(1).map(l => Object.fromEntries(h.map((k,i) => [k.trim(), l.split(',')[i]?.trim()])));
  console.log(JSON.stringify(rows, null, 2));
"
bash — Miller (mlr) pour CSV vers JSON
# Miller est un couteau suisse pour les données structurées
# Installation : brew install miller (macOS) ou apt install miller (Debian/Ubuntu)
mlr --icsv --ojson cat inventory.csv

# Filtrer les lignes lors de la conversion
mlr --icsv --ojson filter '$quantity > 100' inventory.csv

# Sélectionner des colonnes spécifiques
mlr --icsv --ojson cut -f sku,warehouse,quantity inventory.csv
bash — csvtojson CLI
# Installation globale
npm install -g csvtojson

# Convertir un fichier
csvtojson servers.csv > servers.json

# Piper depuis stdin
cat exports/q1-metrics.csv | csvtojson > q1-metrics.json

Pour les gros fichiers, Miller est généralement le meilleur choix par rapport à csvtojson. Miller est implémenté en C et traite le CSV en flux sans charger le fichier entier en mémoire, ce qui lui permet de gérer des exports de plusieurs gigaoctets avec une utilisation mémoire constante. Il supporte aussi les opérations au niveau des champs en place — renommer des colonnes, contraindre les types, filtrer les lignes — avant que les données ne deviennent du JSON, évitant ainsi un pipeline d'analyse-puis-transformation en deux étapes. csvtojson, en revanche, tourne dans Node.js et est plus pratique quand le reste de ta chaîne d'outils est en JavaScript : tu peux piper sa sortie directement dans les streams Node, l'importer comme bibliothèque, ou utiliser son API colParser pour la coercition de type par colonne dans le code. Préfère Miller pour le débit brut et les pipelines shell ; préfère csvtojson quand tu as besoin d'une intégration étroite avec une application Node.js.

Note :jq n'analyse pas le CSV nativement. Si tu as besoin de jq dans le pipeline, convertis d'abord en JSON avec csvtojson ou mlr, puis pipe la sortie JSON vers jq pour le filtrage et la transformation.

Alternative haute performance — PapaParse

L'approche manuelle avec split(',') échoue sur les fichiers CSV du monde réel. Les champs entre guillemets contenant des virgules, les sauts de ligne intégrés, les guillemets doubles échappés — tout cela casse un découpeur naïf. PapaParse est la bibliothèque vers laquelle je me tourne quand le CSV provient d'une source inconnue. Elle gère chaque cas limite RFC 4180, détecte automatiquement les délimiteurs, et fonctionne aussi bien dans Node.js que dans les navigateurs.

bash — installer PapaParse
npm install papaparse
JavaScript — PapaParse avec coercition de types
import Papa from 'papaparse'

const csv = `product,description,price,in_stock
"Widget, Large","A premium widget with ""extra"" features",29.99,true
Bolt Assembly,Standard M8 bolt kit,4.50,true
"Gasket Set","Includes gasket, seal, and O-ring",12.75,false`

const { data, errors, meta } = Papa.parse(csv, {
  header: true,
  dynamicTyping: true,     // convertit automatiquement les nombres et booléens
  skipEmptyLines: true,
  transformHeader: h => h.trim().toLowerCase().replace(/\s+/g, '_'),
})

if (errors.length > 0) {
  console.error('Erreurs d'analyse :', errors)
}

console.log(JSON.stringify(data, null, 2))
// [
//   {
//     "product": "Widget, Large",
//     "description": "A premium widget with \"extra\" features",
//     "price": 29.99,
//     "in_stock": true
//   },
//   ...
// ]
console.log(`${data.length} lignes analysées, délimiteur : "${meta.delimiter}"`)

L'option dynamicTyping de PapaParse effectue la coercition de type automatiquement — les nombres deviennent des nombres, "true"/"false" deviennent des booléens. Le callback transformHeader normalise les noms de colonnes en snake_case, ce qui évite de traiter des en-têtes incohérents venant de différents exports CSV. Pour des conversions rapides sans écrire de code d'analyse, le convertisseur CSV vers JSON gère tout cela dans le navigateur.

Sortie terminal avec coloration syntaxique

Afficher un grand tableau JSON dans le terminal fait rapidement fatiguer les yeux. Ajouter de la coloration syntaxique à la sortie la rend lisible lors du débogage et du développement. Le package cli-highlight colorise la sortie JSON dans les terminaux Node.js.

bash — installer cli-highlight
npm install cli-highlight
JavaScript — sortie JSON colorisée dans le terminal
import { highlight } from 'cli-highlight'

// Après la conversion du CSV en tableau JSON
const jsonOutput = JSON.stringify(rows, null, 2)

// Afficher avec coloration syntaxique
console.log(highlight(jsonOutput, { language: 'json' }))
// Clés, chaînes, nombres et booléens ont chacun une couleur distincte

La sortie colorisée mérite son utilité quand tu inspectes un grand résultat de conversion de manière interactive. Les clés JSON, les valeurs de chaînes, les nombres et les booléens ont chacun des couleurs ANSI distinctes, ce qui facilite l'identification d'un champ dont le type est incorrect — par exemple, un numéro de port qui devrait être 8080 mais qui est surligné comme une chaîne parce que la coercition était désactivée. C'est particulièrement utile lors du débogage de fichiers CSV exportés depuis des tableurs où les types de colonnes sont incohérents d'une ligne à l'autre. Sans couleur, analyser 50 lignes de JSON pour trouver un seul champ mal typé signifie lire chaque valeur individuellement. Avec la couleur, un nombre colorié en chaîne saute aux yeux immédiatement.

Attention :La coloration syntaxique ajoute des codes d'échappement ANSI à la sortie. Ne l'utilise pas quand tu écris du JSON dans un fichier, que tu pipes vers un autre programme ou que tu envoies comme corps d'une réponse API — les codes d'échappement corrompraient le JSON. Utilise la coloration uniquement pour l'affichage dans le terminal.

Travailler avec de gros fichiers CSV

Charger un fichier CSV de 500 Mo dans une chaîne avec readFileSync() va consommer de la mémoire et potentiellement faire planter ton processus. Pour les gros fichiers, traite le CSV ligne par ligne en flux et émets les objets JSON au fur et à mesure. Le package csv-parse (faisant partie de l'écosystème csv sur npm) fournit un analyseur en flux qui fonctionne avec les streams Node.js.

Streaming CSV vers NDJSON avec csv-parse

NDJSON (JSON délimité par des sauts de ligne) est un format où chaque ligne du fichier de sortie est un objet JSON autonome. Contrairement à un seul grand tableau JSON — qui nécessite que le fichier entier soit en mémoire avant de pouvoir commencer à le lire — les fichiers NDJSON peuvent être traités ligne par ligne. Cela rend NDJSON idéal pour les grands ensembles de données qui seront consommés par des processeurs de logs, des pipelines de flux, ou des bases de données avec des API d'import en masse. Le package csv-parse émet un objet JavaScript par ligne CSV en mode objet, tu peux donc le piper directement dans un stream de transformation qui ajoute \n après chaque JSON.stringify(row).

Node.js 18+ — streaming CSV vers NDJSON
import { createReadStream, createWriteStream } from 'node:fs'
import { parse } from 'csv-parse'
import { Transform } from 'node:stream'
import { pipeline } from 'node:stream/promises'

// Transformer chaque objet ligne CSV en ligne JSON
const toNdjson = new Transform({
  objectMode: true,
  transform(record, encoding, callback) {
    callback(null, JSON.stringify(record) + '\n')
  },
})

await pipeline(
  createReadStream('telemetry-2026-03.csv'),
  parse({
    columns: true,       // utiliser la première ligne comme en-têtes
    skip_empty_lines: true,
    trim: true,
    cast: true,          // convertir automatiquement les nombres et booléens
  }),
  toNdjson,
  createWriteStream('telemetry-2026-03.ndjson')
)

console.log('Conversion en flux terminée')
// Chaque ligne du fichier de sortie est un objet JSON :
// {"timestamp":"2026-03-15T08:22:00Z","service":"gateway","latency_ms":42,"status":200}
// {"timestamp":"2026-03-15T08:22:01Z","service":"auth","latency_ms":156,"status":401}
// ...

Streaming PapaParse pour navigateur et Node.js

Le mode streaming de PapaParse utilise un callback step qui se déclenche une fois par ligne plutôt que de collecter toutes les lignes en mémoire. Tu lui passes un ReadStream Node.js (dans Node.js) ou un objet File (dans le navigateur) et PapaParse gère le découpage en chunks en interne. Aucun pipeline de stream à câbler — juste un callback. Utilise-le quand tu as besoin de la conformité RFC 4180 sans intégrer csv-parse.

Node.js — streaming PapaParse sur un gros fichier
import Papa from 'papaparse'
import { createReadStream } from 'node:fs'

let rowCount = 0
const errors = []

const fileStream = createReadStream('warehouse-inventory.csv')

Papa.parse(fileStream, {
  header: true,
  dynamicTyping: true,
  step(result) {
    // Traiter une ligne à la fois — mémoire constante
    rowCount++
    if (result.data.quantity === 0) {
      errors.push(`Ligne ${rowCount} : ${result.data.sku} est en rupture de stock`)
    }
  },
  complete() {
    console.log(`${rowCount} lignes traitées`)
    if (errors.length > 0) {
      console.log(`Problèmes trouvés : ${errors.length}`)
      errors.forEach(e => console.log(`  ${e}`))
    }
  },
  error(err) {
    console.error('Analyse échouée :', err.message)
  },
})
Note :Passe en streaming quand ton fichier CSV dépasse 50 Mo ou quand tu traites une entrée non bornée (flux WebSocket, server-sent events, stdin en pipe). Le format NDJSON (un objet JSON par ligne) est souvent un meilleur format de sortie qu'un grand tableau JSON pour les grands ensembles de données — il peut être traité ligne par ligne sans charger le fichier entier en mémoire.

Erreurs courantes

Appeler JSON.parse() directement sur une chaîne CSV

Problème : CSV n'est pas du JSON. Passer une chaîne CSV brute à JSON.parse() lève une SyntaxError car les virgules et les sauts de ligne ne sont pas une syntaxe JSON valide.

Solution : Analyse d'abord le CSV en objets JavaScript avec split() ou une bibliothèque, puis utilise JSON.stringify() pour produire du JSON. N'appelle JSON.parse() que sur des chaînes qui sont déjà du JSON valide.

Before · JavaScript
After · JavaScript
const csv = 'name,email\nMarie Dupont,mdupont@nexuslabs.io'
const data = JSON.parse(csv)
// SyntaxError: Unexpected token 'a'
const csv = 'name,email\nMarie Dupont,mdupont@nexuslabs.io'
const lines = csv.trim().split('\n')
const headers = lines[0].split(',')
const rows = lines.slice(1).map(line =>
  Object.fromEntries(headers.map((h, i) => [h, line.split(',')[i]]))
)
const json = JSON.stringify(rows, null, 2)  // chaîne JSON valide
Utiliser toString() à la place de JSON.stringify()

Problème : Appeler toString() sur un objet JavaScript retourne la chaîne inutile '[object Object]' au lieu des données réelles. Cela détruit silencieusement ta sortie CSV vers JSON.

Solution : Utilise toujours JSON.stringify() pour convertir des objets JavaScript en chaînes JSON. toString() existe pour la coercition primitive vers chaîne, pas pour la sérialisation.

Before · JavaScript
After · JavaScript
const row = { server: 'api-gateway', port: 8080 }
const output = row.toString()
// "[object Object]"  — les données sont perdues
const row = { server: 'api-gateway', port: 8080 }
const output = JSON.stringify(row, null, 2)
// '{"server":"api-gateway","port":8080}'
Découper sur la virgule sans gérer les champs entre guillemets

Problème : Un simple split(",") échoue quand les valeurs CSV contiennent des virgules dans des champs entre guillemets : "Widget, Large" devient deux valeurs séparées au lieu d'une.

Solution : Utilise PapaParse ou csv-parse pour toute donnée CSV que tu ne contrôles pas totalement. Si tu dois analyser manuellement, implémente un analyseur à machine d'état qui suit si la position actuelle est à l'intérieur d'un champ entre guillemets.

Before · JavaScript
After · JavaScript
const line = '"Widget, Large","Premium quality",29.99'
const values = line.split(',')
// ["\"Widget", " Large\"", "\"Premium quality\"", "29.99"]
// 4 valeurs au lieu de 3 — premier champ découpé incorrectement
import Papa from 'papaparse'
const { data } = Papa.parse('"Widget, Large","Premium quality",29.99')
// data[0] = ["Widget, Large", "Premium quality", "29.99"]
// 3 valeurs, correctement analysées
Oublier que toutes les valeurs CSV sont des chaînes

Problème : Sans coercition de type, port: "8080" reste une chaîne dans le JSON au lieu d'être un nombre. Les systèmes en aval attendant des types numériques rejettent ou gèrent mal les données.

Solution : Applique une coercition de type explicite lors de l'étape de mapping, ou utilise PapaParse avec dynamicTyping: true. Sois toujours délibéré sur les champs qui doivent être numériques.

Before · JavaScript
After · JavaScript
const row = { port: '8443', debug: 'true', workers: '4' }
JSON.stringify(row)
// {"port":"8443","debug":"true","workers":"4"}  — tout est chaîne
const row = {
  port: Number('8443'),           // 8443
  debug: 'true' === 'true',      // true
  workers: Number('4'),           // 4
}
JSON.stringify(row)
// {"port":8443,"debug":true,"workers":4}  — types corrects

Analyse manuelle vs bibliothèques — Comparaison rapide

Méthode
Sortie formatée
JSON valide
Types personnalisés
Streaming
Installation requise
JSON.stringify()
✓ (avec space)
✓ via toJSON()/replacer
Non (intégré)
JSON.parse()
N/A (analyse)
✓ (valide)
✓ via reviver
Non (intégré)
csv-parse (Node.js)
✗ (retourne des objets)
✗ (pas JSON)
npm install
PapaParse
✗ (retourne des objets)
✗ (pas JSON)
npm install
csvtojson
✓ via colParser
npm install
jq (CLI)
N/A
Installation système
Miller (CLI)
N/A
Installation système

Pour les scripts rapides où tu contrôles le format CSV et sais qu'il n'y a pas de champs entre guillemets, l'approche intégrée split() + JSON.stringify() fonctionne et ne requiert aucune dépendance. Pour les systèmes de production traitant des fichiers CSV uploadés par des utilisateurs, utilise PapaParse dans le navigateur ou csv-parse dans Node.js — les deux gèrent RFC 4180 correctement et supportent le streaming. Le package csvtojson est le seul à produire du JSON directement, gérant à la fois l'analyse et la sérialisation en un seul appel. Quand tu as besoin du chemin le plus rapide du collé au résultat, le convertisseur CSV vers JSON gère tout cela dans le navigateur sans aucune configuration.

Questions fréquentes

Comment convertir du CSV en JSON en JavaScript sans bibliothèque ?

Découpe la chaîne CSV par saut de ligne pour obtenir les lignes, extrait les en-têtes de la première ligne avec split(","), puis mappe les lignes restantes en objets dont les clés viennent de ces en-têtes. Termine avec JSON.stringify(array, null, 2) pour produire une chaîne JSON formatée. Cette approche fonctionne bien pour les fichiers CSV simples dont tu contrôles le format et dont tu sais qu'il n'y a pas de champs entre guillemets ni de virgules intégrées. Pour les données issues d'exports de tableurs ou de systèmes tiers, les champs entre guillemets et les valeurs multi-lignes casseront un découpeur naïf — utilise PapaParse ou csv-parse dans ces cas. Pour les très petits fichiers traités dans le navigateur, cette approche sans dépendance est idéale.

JavaScript
const csv = `name,email,department
Marie Dupont,mdupont@nexuslabs.io,Engineering
Thomas Martin,tmartin@nexuslabs.io,Product`

const lines = csv.trim().split('\n')
const headers = lines[0].split(',')
const rows = lines.slice(1).map(line => {
  const values = line.split(',')
  return Object.fromEntries(headers.map((h, i) => [h.trim(), values[i]?.trim()]))
})

console.log(JSON.stringify(rows, null, 2))
// [
//   { "name": "Marie Dupont", "email": "mdupont@nexuslabs.io", "department": "Engineering" },
//   { "name": "Thomas Martin", "email": "tmartin@nexuslabs.io", "department": "Product" }
// ]

Quelle est la différence entre JSON.stringify() et toString() pour les objets ?

toString() sur un objet ordinaire retourne la chaîne inutile "[object Object]" — elle ne dit rien sur les données réelles. JSON.stringify() produit une chaîne JSON valide avec toutes les clés et valeurs correctement sérialisées, y compris les objets et tableaux imbriqués. Utilise toujours JSON.stringify() quand tu dois convertir un objet JavaScript (comme une ligne issue d'un CSV) en chaîne JSON. Pour l'opération inverse — reconstruire des objets JavaScript vivants depuis une chaîne JSON — utilise JSON.parse(), qui est l'exact inverse de JSON.stringify(). Ces deux fonctions forment un cycle complet : stringify pour persister ou transmettre les données, parse pour les consommer.

JavaScript
const row = { name: 'Marie Dupont', role: 'Engineer' }

console.log(row.toString())       // "[object Object]"
console.log(JSON.stringify(row))   // '{"name":"Marie Dupont","role":"Engineer"}'

Comment gérer les champs CSV contenant des virgules ou des guillemets ?

RFC 4180 spécifie que les champs contenant des virgules, des sauts de ligne ou des guillemets doubles doivent être entourés de guillemets doubles, les guillemets intégrés étant échappés en les doublant ("" dans un champ entre guillemets représente un guillemet littéral simple). Un simple split(",") manuel échoue sur ces fichiers — la frontière de champ n'est plus une virgule ordinaire. Utilise PapaParse ou csv-parse pour les données de production, ou écris un analyseur à machine d'état qui suit si tu es à l'intérieur d'un champ entre guillemets. Écrire une machine d'état correcte de zéro est étonnamment délicat : tu dois gérer les guillemets en début de champ, les guillemets échappés en milieu de champ, les sauts de ligne dans les champs entre guillemets, et les différentes conventions de fin de ligne (CRLF vs LF). Pour tout ce qui dépasse des données CSV de test, utilise une bibliothèque éprouvée.

JavaScript
// PapaParse gère RFC 4180 correctement
import Papa from 'papaparse'

const csv = `product,description,price
"Widget, Large","A big ""widget""",29.99
Bolt,Standard bolt,1.50`

const { data } = Papa.parse(csv, { header: true })
console.log(JSON.stringify(data, null, 2))
// description field correctly contains: A big "widget"

Peut-on convertir du CSV en JSON directement dans le navigateur ?

Oui. JSON.stringify() et JSON.parse() sont intégrés dans tous les moteurs de navigateur. Pour l'étape d'analyse du CSV, tu peux découper par saut de ligne et virgule pour les fichiers simples, ou inclure PapaParse via un CDN (il n'a pas de dépendances Node.js). Toute la conversion se fait côté client sans aller-retour vers le serveur, ce qui est utile pour la confidentialité des fichiers — les données CSV brutes ne quittent jamais la machine de l'utilisateur. Quand un utilisateur télécharge un fichier CSV via un élément <input type="file">, la méthode file.text() de l'API File retourne une Promise qui se résout en le contenu du fichier sous forme de chaîne, que tu peux ensuite passer à ta fonction de conversion. Cela rend la conversion CSV vers JSON entièrement dans le navigateur pratique pour les tableaux de bord, les outils de développement, et toute application ayant besoin de traiter des données uploadées sans backend.

JavaScript
// Navigateur : l'utilisateur uploade un fichier CSV
const fileInput = document.querySelector('input[type="file"]')
fileInput.addEventListener('change', async (event) => {
  const file = event.target.files[0]
  const text = await file.text()
  const lines = text.trim().split('\n')
  const headers = lines[0].split(',')
  const rows = lines.slice(1).map(line =>
    Object.fromEntries(headers.map((h, i) => [h.trim(), line.split(',')[i]?.trim()]))
  )
  console.log(JSON.stringify(rows, null, 2))
})

Comment analyser les valeurs numériques et booléennes d'un CSV au lieu de tout garder comme chaînes ?

CSV n'a pas de système de types — chaque champ est une chaîne. Tu dois contraindre les valeurs lors de l'étape de mapping. Vérifie les motifs numériques avec Number() ou parseFloat(), convertis "true"/"false" en booléens, et traite les chaînes vides comme null. Fais attention aux champs qui ressemblent à des nombres mais doivent rester des chaînes : les codes postaux comme "75001" perdent leur zéro initial quand ils sont convertis avec Number(), et les numéros de téléphone ou codes produit avec des caractères numériques sont tout aussi fragiles. La bibliothèque csvtojson effectue la coercition de type automatique via son option colParser, qui te permet de spécifier des fonctions de conversion par colonne et de remplacer l'auto-détection pour les colonnes problématiques. L'option dynamicTyping de PapaParse applique la même coercition globalement sur toutes les colonnes.

JavaScript
function coerceValue(val) {
  if (val === '') return null
  if (val === 'true') return true
  if (val === 'false') return false
  const num = Number(val)
  if (!isNaN(num) && val.trim() !== '') return num
  return val
}

// Appliqué lors du mapping CSV vers objet
const row = { port: coerceValue('8443'), debug: coerceValue('true'), host: coerceValue('api.internal') }
// { port: 8443, debug: true, host: "api.internal" }

Comment écrire la sortie CSV vers JSON dans un fichier avec Node.js ?

Utilise fs.writeFileSync() avec la sortie de JSON.stringify(). Le troisième argument de JSON.stringify contrôle l'indentation — passe 2 pour deux espaces ou "\t" pour des tabulations. Pour lire le fichier en retour, utilise JSON.parse(fs.readFileSync(path, "utf8")), qui reconstruit le tableau JavaScript vivant d'objets. Si tu écris le fichier dans un contexte asynchrone (à l'intérieur d'une fonction async ou au niveau supérieur d'un module ES), préfère fs.promises.writeFile() pour éviter de bloquer la boucle d'événements pendant l'écriture du fichier. Pour les sorties JSON volumineuses de plusieurs mégaoctets, envisage de passer un flux JSON vers un WriteStream plutôt que de construire la chaîne entière en mémoire avant d'écrire.

JavaScript
import { writeFileSync, readFileSync } from 'node:fs'

// Écriture
const jsonOutput = JSON.stringify(rows, null, 2)
writeFileSync('employees.json', jsonOutput, 'utf8')

// Lecture en retour
const parsed = JSON.parse(readFileSync('employees.json', 'utf8'))
console.log(Array.isArray(parsed))  // true
console.log(parsed[0].name)         // "Marie Dupont"

Outils associés

Aussi disponible en :Python
AC
Alex ChenFront-end & Node.js Developer

Alex is a front-end and Node.js developer with extensive experience building web applications and developer tooling. He is passionate about web standards, browser APIs, and the JavaScript ecosystem. In his spare time he contributes to open-source projects and writes about modern JavaScript patterns, performance optimisation, and everything related to the web platform.

SL
Sophie LaurentRéviseur technique

Sophie is a full-stack developer focused on TypeScript across the entire stack — from React frontends to Express and Fastify backends. She has a particular interest in type-safe API design, runtime validation, and the patterns that make large JavaScript codebases stay manageable. She writes about TypeScript idioms, Node.js internals, and the ever-evolving JavaScript module ecosystem.