CSV to JSON JavaScript — Converter + Code Examples

·Front-end & Node.js Developer·ПеревіреноSophie Laurent·Опубліковано

Використовуйте безкоштовний CSV to JSON прямо в браузері — без встановлення.

Спробувати CSV to JSON онлайн →

Більшість CSV-даних надходить у вигляді плаского рядка із завантаженого файлу, експорту бази даних або API, що досі використовує формат 1970-х. Щоб конвертувати CSV у JSON у JavaScript, потрібні дві речі, які мова надає безкоштовно: розбиття рядків для розбору рядків і JSON.stringify() для серіалізації результату. Для основ пакети npm не потрібні — цей посібник охоплює повний конвеєр від повторно використовуваної утиліти csvToJson() до PapaParse і файлового введення/виведення у Node.js. Для швидких конвертацій без коду онлайн-конвертер CSV у JSON впорається миттєво. Усі приклади орієнтовані на Node.js 18+ та сучасні браузери.

  • Розбийте CSV по рядках, витягніть заголовки з рядка 0, перетворіть решту рядків на об'єкти, а потім JSON.stringify(array, null, 2) для форматованого виводу.
  • JSON.stringify() формує рядок; JSON.parse() перетворює його назад на живий JavaScript-масив — знайте, яке з них ви маєте, перш ніж з ним працювати.
  • Екземпляри Map не серіалізуються у JSON автоматично — спочатку викличте Object.fromEntries(map).
  • Для CSV з полями у лапках, комами всередині значень або символами нового рядка у клітинках використовуйте PapaParse або csv-parse замість ручного розбиття.
  • csvtojson (npm) обробляє приведення типів, стрімінг та граничні випадки RFC 4180 в одному виклику.

Що таке конвертація CSV у JSON?

Конвертація CSV у JSON перетворює плаский, розділений комами текстовий формат на структурований масив об'єктів, де кожен рядок стає JavaScript-об'єктом з ключами, що відповідають заголовкам стовпців. Формат CSV не має типів даних — усе є рядком. JSON додає структуру, вкладеність та явні типи (числа, булеві значення, null). Ця конвертація є першим кроком майже у кожному конвеєрі даних, що починається з експорту таблиці, дампа застарілої системи або файлу, завантаженого користувачем. Самі дані залишаються незмінними; формат змінюється з позиційних стовпців на іменовані властивості.

Before · json
After · json
name,email,role,active
Олександр Коваленко,o.kovalenko@nexuslabs.io,Engineering Lead,true
Марія Шевченко,m.shevchenko@nexuslabs.io,Product Manager,true
[
  {
    "name": "Олександр Коваленко",
    "email": "o.kovalenko@nexuslabs.io",
    "role": "Engineering Lead",
    "active": "true"
  },
  {
    "name": "Марія Шевченко",
    "email": "m.shevchenko@nexuslabs.io",
    "role": "Product Manager",
    "active": "true"
  }
]

csvToJson() — Побудова функції конвертації для повторного використання

Повний конвеєр CSV→JSON у JavaScript розбивається на три кроки: розбийте CSV-рядок по символу нового рядка для отримання рядків, витягніть заголовки з першого рядка за допомогою split(','), а потім перетворіть кожен наступний рядок на простий JavaScript-об'єкт, де ключі беруться із заголовків, а значення — з відповідних позицій стовпців. Фінальний виклик JSON.stringify() перетворює масив об'єктів у JSON-рядок. Ось мінімальна робоча версія:

JavaScript — мінімальна csvToJson
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,us-east-1,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": "us-east-1", "status": "healthy" },
//   { "server": "auth-service", "port": "8443", "region": "eu-west-1", "status": "degraded" },
//   { "server": "payments-api", "port": "9090", "region": "ap-south-1", "status": "healthy" }
// ]

Ця функція обробляє основні випадки: завершальні символи нового рядка, порожні рядки, пробіли навколо значень. Кожне поле CSV передається як рядок. Зверніть увагу, що port має значення "8080" (рядок), а не 8080 (число). Якщо вам потрібні правильні типи у JSON-виводі, доведеться приводити їх самостійно. Ось розширена версія з визначенням типів:

JavaScript — csvToJson з приведенням типів
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 }
// ]

Прапорець coerce є увімкненим за запитом, бо автоматичне визначення типів може дати збій — поле на кшталт поштового індексу ("07302") втрачає початковий нуль при перетворенні в число. Вимикайте приведення типів за замовчуванням і вмикайте лише тоді, коли ви контролюєте схему. Коротка замітка: JSON.stringify() приймає третій аргумент space для відступів. Передайте 2 для двох пробілів, 4 для чотирьох, або "\t" для табуляції. Повністю опустіть його для компактного однорядкового виводу — корисно при відправці JSON-рядка у тілі запиту до API, де пробільні символи лише витрачають пропускну здатність.

Примітка:Необроблений CSV-рядок — це не JSON. Виклик JSON.parse() безпосередньо на CSV-тексті викидає SyntaxError. Спочатку потрібно перетворити CSV на JavaScript-об'єкти за допомогою функції csvToJson(), яка всередині викликає JSON.stringify() для отримання фактичного JSON-рядка.

Обробка Map, Date та власних об'єктів із CSV-даних

Не кожна конвертація CSV завершується пласким масивом простих об'єктів. Іноді потрібно побудувати Map з пар заголовок-значення, перетворити рядки дат на об'єкти Date або прикріпити обчислені властивості перед серіалізацією. У JavaScript є одна особливість, яка регулярно підводить: екземпляри Map не серіалізуються за допомогою JSON.stringify(). Ви отримаєте порожній об'єкт. Рішення — Object.fromEntries() для перетворення Map на простий об'єкт перед серіалізацією.

Причина, чому Map серіалізується у {}, полягає в тому, що JSON.stringify() перебирає власні перелічувані властивості об'єкта. Map зберігає свої записи у внутрішньому слоті, а не як перелічувані властивості самого об'єкта, тому серіалізатор бачить об'єкт без ключів. Прототип Map також не має методу toJSON(), який є гачком, що JSON.stringify() першочергово викликає для будь-якого значення перш ніж вирішити, як його серіалізувати. Якщо значення має toJSON(), повернуте методом значення і серіалізується — не сам об'єкт. Саме тому об'єкти Date серіалізуються коректно: Date.prototype.toJSON повертає рядок ISO 8601, тому JSON.stringify(new Date()) формує рядок з часовою міткою у лапках, а не порожній об'єкт. Розуміння цього гачка дозволяє визначити таку ж поведінку у власних класах — як показано у прикладі з EmployeeRecord нижче — щоб точно контролювати, які поля з CSV потраплять у фінальний JSON-вивід.

Перетворення Map у JSON

JavaScript — Map у JSON через Object.fromEntries()
// Побудова Map з пар заголовок→значення 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 НЕ серіалізується безпосередньо
console.log(JSON.stringify(rowMap))
// "{}"  — порожній об'єкт, дані втрачено!

// Спочатку перетворіть на простий об'єкт
const rowObj = Object.fromEntries(rowMap)
console.log(JSON.stringify(rowObj, null, 2))
// {
//   "server": "payments-api",
//   "port": "9090",
//   "region": "ap-south-1"
// }

Рядки дат та toJSON()

Поля дат у CSV надходять як рядки. Якщо ви перетворюєте їх на об'єкти Date під час обробки, ці Date серіалізуються коректно, бо Date має вбудований метод toJSON(), що повертає рядок ISO 8601. Також можна визначити власний toJSON() у власних класах для контролю того, які стовпці CSV з'являться в серіалізованому виводі — наприклад, опускаючи внутрішні поля відстеження на кшталт _rowIndex.

JavaScript — toJSON() для власної серіалізації
class EmployeeRecord {
  constructor(csvRow) {
    this._rowIndex = csvRow._rowIndex  // внутрішнє, не для JSON
    this.employeeId = csvRow.employee_id
    this.name = csvRow.name
    this.hiredAt = new Date(csvRow.hired_date)
    this.salary = Number(csvRow.salary)
  }

  toJSON() {
    // Експортуємо лише поля, потрібні у JSON-виводі
    return {
      employee_id: this.employeeId,
      name: this.name,
      hired_at: this.hiredAt,  // Date.toJSON() → ISO-рядок автоматично
      salary: this.salary,
    }
  }
}

const csvRow = {
  _rowIndex: 42,
  employee_id: 'EMP-2847',
  name: 'Олександр Коваленко',
  hired_date: '2024-03-15',
  salary: '128000',
}

const record = new EmployeeRecord(csvRow)
console.log(JSON.stringify(record, null, 2))
// {
//   "employee_id": "EMP-2847",
//   "name": "Олександр Коваленко",
//   "hired_at": "2024-03-15T00:00:00.000Z",
//   "salary": 128000
// }
// Примітка: _rowIndex виключено, salary є числом, дата у форматі ISO

Reviver для десеріалізації дат

Після запису JSON, отриманого з CSV, у файл або відправки через мережу, JSON.parse() повертає прості об'єкти — об'єкти Date знову стають рядками. Використовуйте функцію reviver для перетворення рядків ISO 8601 назад на об'єкти Date під час розбору:

JavaScript — reviver для відновлення об'єктів Date
const jsonString = '{"employee_id":"EMP-2847","name":"Олександр Коваленко","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
Увага:JSON.stringify() повертає undefined (а не рядок) для значень, що містять функції, Symbols або властивості зі значенням undefined. Якщо ваші об'єкти, отримані з CSV, випадково отримали значення undefined від відсутнього стовпця, ця властивість непомітно зникне з JSON-виводу. Завжди замінюйте відсутні значення на null.

Довідка параметрів JSON.stringify()

Сигнатура функції: JSON.stringify(value, replacer?, space?). Аргументи replacer та space є необов'язковими — передавайте null для replacer, коли потрібен лише відступ.

Параметр
Тип
За замовчуванням
Опис
value
any
(обов'язковий)
JavaScript-значення для серіалізації — об'єкт, масив, рядок, число, булеве значення або null
replacer
Function | Array | null
undefined
Фільтрує або перетворює значення під час серіалізації. Масив задає білий список імен властивостей; функція отримує пари (key, value)
space
number | string
undefined
Відступ: число 0–10 для пробілів, рядок (наприклад "\t") для власного відступу. Опустіть для компактного однорядкового виводу

Параметри JSON.parse():

Параметр
Тип
За замовчуванням
Опис
text
string
(обов'язковий)
JSON-рядок для розбору — має бути валідним JSON, інакше викидається SyntaxError
reviver
Function | undefined
undefined
Викликається для кожної пари ключ-значення. Повернуте значення замінює оригінальне; return undefined видаляє властивість

JSON.parse() — Споживання JSON-виводу

Отримавши JSON-рядок від csvToJson(), наступним кроком зазвичай є його розбір назад на живий JavaScript-масив для фільтрації, відображення або передачі до API. Різниця між JSON-рядком (typeof === "string") та JavaScript-об'єктом має значення. Не можна викликати .filter() або звернутися до [0].name у рядка — спочатку потрібен JSON.parse(). Цей цикл (stringify, потім parse) також працює як техніка валідації: якщо конвертація CSV з якоїсь причини сформувала некоректний JSON, parse викине помилку. Необов'язковий аргумент reviver дозволяє перетворювати кожну пару ключ-значення під час розбору — корисно для відновлення об'єктів Date з ISO-рядків або перейменування ключів без окремого проходу.

JavaScript — розбір JSON-виводу та запити до рядків
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`

// Крок 1: конвертуємо CSV у JSON-рядок
const jsonString = csvToJson(csv, { coerce: true })

// Крок 2: розбираємо назад у JavaScript-масив
const endpoints = JSON.parse(jsonString)

// Перевіряємо, що це масив
console.log(Array.isArray(endpoints))  // true

// Фільтруємо повільні ендпоінти
const slow = endpoints.filter(ep => ep.avg_latency_ms > 200)
console.log(slow.map(ep => ep.endpoint))
// ["/api/v2/orders", "/api/v2/payments"]

// Деструктуруємо перший рядок
const [first, ...rest] = endpoints
console.log(first.endpoint)  // "/api/v2/orders"
console.log(rest.length)     // 3

Безпечна обгортка для JSON.parse() корисна при валідації результату конвертації перед подальшою обробкою. Якщо конвертація CSV з будь-якої причини формує неправильний JSON (обрізане введення, помилки кодування), це перехопить помилку без аварійного завершення:

JavaScript — безпечна обгортка parse
function safeParse(jsonString) {
  try {
    return { data: JSON.parse(jsonString), error: null }
  } catch (err) {
    return { data: null, error: err.message }
  }
}

// Валідний вивід
const result = safeParse(csvToJson(csv))
if (result.error) {
  console.error('CSV conversion produced invalid JSON:', result.error)
} else {
  console.log(`Parsed ${result.data.length} rows`)
}

// Випадкова передача необробленого CSV у JSON.parse — це не спрацює
const bad = safeParse('name,email\nОлександр,o.kovalenko@nexuslabs.io')
console.log(bad.error)  // "Unexpected token 'О', "name,email"... is not valid JSON"

Reviver для перейменування ключів та валідації

Функція reviver отримує кожну пару ключ-значення під час розбору, від найглибших властивостей до зовнішніх. Повернення undefined для ключа повністю видаляє його з результату; повернення іншого значення замінює оригінальне. Reviver корисний для перейменування заголовків (camelCase у snake_case), видалення внутрішніх полів або перевірки наявності обов'язкових стовпців. Він викликається з кореневим значенням останнім (порожній рядок як ключ) — там і слід кидати помилку, якщо результат не є масивом.

JavaScript — reviver для перейменування ключів та валідації форми
const jsonString = csvToJson(`employeeId,firstName,hiredDate
EMP-2847,Олександр,2024-03-15
EMP-3012,Марія,2023-11-01`, { coerce: false })

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

const employees = JSON.parse(jsonString, function(key, value) {
  // Кореневе значення — валідуємо форму
  if (key === '') {
    if (!Array.isArray(value)) throw new Error('Expected JSON array from CSV')
    return value
  }
  // Перейменовуємо ключі camelCase на 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: 'Олександр', hired_date: '2024-03-15' }

Конвертація CSV з файлу та відповіді API

Два місця, звідки CSV-дані реально надходять у виробничому середовищі: файли на диску та HTTP-відповіді. Обидва сценарії потребують обробки помилок, бо введення зовнішнє і неконтрольоване.

Зчитування CSV-файлу, конвертація, запис JSON

Node.js 18+ — конвертація файлу
import { readFileSync, writeFileSync } from 'node:fs'

function csvToJsonFromFile(inputPath, outputPath) {
  let csvText
  try {
    csvText = readFileSync(inputPath, 'utf8')
  } catch (err) {
    throw new Error(`Failed to read ${inputPath}: ${err.message}`)
  }

  const lines = csvText.trim().split('\n')
  if (lines.length < 2) {
    throw new Error(`${inputPath} has no data rows (only ${lines.length} line)`)
  }

  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(`Converted ${rows.length} rows → ${outputPath}`)
  return rows
}

// Використання
const data = csvToJsonFromFile('inventory.csv', 'inventory.json')
console.log(data[0])
// { sku: "WDG-2847", warehouse: "us-east-1", quantity: "150", ... }

Отримання CSV з ендпоінту API

Node.js 18+ — конвертація відповіді 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(`Unexpected content-type: ${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
}

// Приклад: отримання CSV з курсами обміну від постачальника даних
try {
  const rates = await fetchCsvAsJson('https://data.ecb.internal/rates/daily.csv')
  console.log(JSON.stringify(rates.slice(0, 3), null, 2))
  // Відправляємо JSON до подальшого сервісу
  await fetch('https://api.internal/v2/rates', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ data: rates }),
  })
} catch (err) {
  console.error('Rate sync failed:', err.message)
}
Примітка:Аргумент replacer у JSON.stringify() дозволяє задати білий список конкретних стовпців з CSV. Передайте масив імен заголовків, щоб включити лише ці поля: JSON.stringify(rows, ['name', 'email', 'department']). Властивості, не зазначені в масиві, непомітно виключаються з виводу.

Конвертація CSV у JSON через командний рядок

Node.js може виконувати однорядкові скрипти, а також існують спеціалізовані CLI-інструменти для конвертації CSV у JSON без написання скрипту.

bash — однорядковий скрипт Node.js
# Передаємо CSV у однорядковий скрипт Node.js
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) для конвертації CSV у JSON
# Miller — швейцарський армійський ніж для структурованих даних
# Встановлення: brew install miller (macOS) або apt install miller (Debian/Ubuntu)
mlr --icsv --ojson cat inventory.csv

# Фільтрація рядків під час конвертації
mlr --icsv --ojson filter '$quantity > 100' inventory.csv

# Вибір конкретних стовпців
mlr --icsv --ojson cut -f sku,warehouse,quantity inventory.csv
bash — csvtojson CLI
# Глобальне встановлення
npm install -g csvtojson

# Конвертація файлу
csvtojson servers.csv > servers.json

# Передача через stdin
cat exports/q1-metrics.csv | csvtojson > q1-metrics.json

Для великих файлів Miller зазвичай є кращим вибором порівняно з csvtojson. Miller реалізований на C і обробляє CSV як потік без завантаження всього файлу в пам'ять, тобто він обробляє експорти кількох гігабайтів при постійному споживанні пам'яті. Він також підтримує операції на рівні полів безпосередньо — перейменування стовпців, приведення типів, фільтрацію рядків — ще до того, як дані стануть JSON, що дозволяє уникнути двокрокового конвеєру parse-потім-transform. csvtojson, з іншого боку, працює на Node.js і зручніший, коли решта інструментального ланцюжка написана на JavaScript: можна передавати його вивід безпосередньо у потоки Node, імпортувати як бібліотеку або використовувати його API colParser для приведення типів у коді. Надавайте перевагу Miller для максимальної пропускної здатності та shell-конвеєрів; надавайте перевагу csvtojson, коли потрібна тісна інтеграція з Node.js-застосунком.

Примітка:jq не розбирає CSV нативно. Якщо потрібен jq у конвеєрі, спочатку конвертуйте у JSON за допомогою csvtojson або mlr, а потім передавайте JSON-вивід до jq для фільтрації та трансформації.

Альтернатива для продуктивності — PapaParse

Ручний підхід з split(',') не справляється з реальними CSV-файлами. Поля у лапках, що містять коми, вбудовані символи нового рядка, екрановані подвійні лапки — все це ламає наївний розбивач. PapaParse — це бібліотека, яку варто використовувати, коли CSV надходить з невідомого джерела. Вона обробляє всі граничні випадки RFC 4180, автоматично визначає розділювачі та працює як у Node.js, так і в браузерах.

bash — встановлення PapaParse
npm install papaparse
JavaScript — PapaParse з приведенням типів
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,     // автоматично перетворює числа та булеві значення
  skipEmptyLines: true,
  transformHeader: h => h.trim().toLowerCase().replace(/\s+/g, '_'),
})

if (errors.length > 0) {
  console.error('Parse errors:', 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(`Parsed ${data.length} rows, delimiter: "${meta.delimiter}"`)

Опція dynamicTyping PapaParse виконує приведення типів автоматично — числа стають числами, "true"/"false" стають булевими значеннями. Зворотний виклик transformHeader нормалізує імена стовпців до snake_case, що позбавляє від роботи з непослідовними заголовками з різних CSV-експортів. Для швидких конвертацій без написання коду розбору конвертер CSV у JSON робить це все у браузері.

Вивід у терміналі з підсвічуванням синтаксису

Виведення великого JSON-масиву у термінал швидко стомлює очі. Додавання підсвічування синтаксису робить вивід читабельним під час налагодження та розробки. Пакет cli-highlight забарвлює JSON-вивід у терміналах Node.js.

bash — встановлення cli-highlight
npm install cli-highlight
JavaScript — кольоровий JSON-вивід у терміналі
import { highlight } from 'cli-highlight'

// Після конвертації CSV у JSON-масив
const jsonOutput = JSON.stringify(rows, null, 2)

// Виводимо з підсвічуванням синтаксису
console.log(highlight(jsonOutput, { language: 'json' }))
// Ключі, рядки, числа та булеві значення отримують різні кольори

Кольоровий вивід виправдовує себе при інтерактивному перегляді великих результатів конвертації. JSON-ключі, рядкові значення, числа та булеві значення отримують різні ANSI-кольори, що дозволяє легко виявити поле з неправильним типом — наприклад, порт, що має бути 8080, але підсвічений як рядок через вимкнене приведення типів. Це особливо корисно при налагодженні CSV-файлів, експортованих зі табличних інструментів, де типи стовпців непослідовні між рядками. Без кольору перегляд 50 рядків JSON для виявлення одного поля з помилковим типом означає читання кожного значення окремо. З кольором рядок замість числа виділяється одразу.

Увага:Підсвічування синтаксису додає ANSI escape-коди до виводу. Не використовуйте його при записі JSON у файл, передачі до іншої програми або відправці як тіло відповіді API — escape-коди пошкодять JSON. Використовуйте підсвічування лише для відображення у терміналі.

Робота з великими CSV-файлами

Завантаження 500 МБ CSV-файлу у рядок за допомогою readFileSync() з'їсть пам'ять і потенційно завершить процес аварійно. Для великих файлів обробляйте CSV рядок за рядком і емітуйте JSON-об'єкти по мірі надходження. Пакет csv-parse (частина екосистеми csv на npm) надає потоковий парсер, що працює з потоками Node.js.

Потокова конвертація CSV у NDJSON за допомогою csv-parse

NDJSON (Newline-Delimited JSON) — формат, де кожен рядок вихідного файлу є окремим JSON-об'єктом. На відміну від єдиного великого JSON-масиву — для читання якого весь файл має бути в пам'яті — NDJSON-файли можна обробляти рядок за рядком. Це робить NDJSON ідеальним для великих наборів даних, що будуть споживатися обробниками журналів, потоковими конвеєрами або базами даних з API масового імпорту. Пакет csv-parse емітує один JavaScript-об'єкт на рядок CSV в об'єктному режимі, тому можна передавати його безпосередньо у transform-потік, що дописує \n після кожного JSON.stringify(row).

Node.js 18+ — потокова конвертація CSV у NDJSON
import { createReadStream, createWriteStream } from 'node:fs'
import { parse } from 'csv-parse'
import { Transform } from 'node:stream'
import { pipeline } from 'node:stream/promises'

// Перетворюємо кожен об'єкт рядка CSV на рядок 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,       // використовуємо перший рядок як заголовки
    skip_empty_lines: true,
    trim: true,
    cast: true,          // автоматично перетворюємо числа та булеві значення
  }),
  toNdjson,
  createWriteStream('telemetry-2026-03.ndjson')
)

console.log('Streaming conversion complete')
// Кожен рядок вихідного файлу є одним 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}
// ...

Потоковий режим PapaParse для браузера та Node.js

Потоковий режим PapaParse використовує зворотний виклик step, що спрацьовує один раз на рядок замість накопичення всіх рядків у пам'яті. Передайте ReadStream Node.js (у Node.js) або об'єкт File (у браузері), і PapaParse обробляє розбивку на частини внутрішньо. Жодного потокового конвеєру не потрібно — лише зворотний виклик. Використовуйте його, коли потрібна відповідність RFC 4180 без підключення csv-parse.

Node.js — потокова обробка великого файлу PapaParse
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) {
    // Обробляємо по одному рядку — постійне споживання пам'яті
    rowCount++
    if (result.data.quantity === 0) {
      errors.push(`Row ${rowCount}: ${result.data.sku} is out of stock`)
    }
  },
  complete() {
    console.log(`Processed ${rowCount} rows`)
    if (errors.length > 0) {
      console.log(`Issues found: ${errors.length}`)
      errors.forEach(e => console.log(`  ${e}`))
    }
  },
  error(err) {
    console.error('Parse failed:', err.message)
  },
})
Примітка:Переходьте до потокової обробки, коли ваш CSV-файл перевищує 50 МБ або коли ви обробляєте необмежений потік введення (WebSocket feed, server-sent events, piped stdin). Формат NDJSON (один JSON-об'єкт на рядок) часто є кращим форматом виводу, ніж великий JSON-масив для великих наборів даних — його можна обробляти рядок за рядком без завантаження всього файлу в пам'ять.

Типові помилки

Виклик JSON.parse() безпосередньо на CSV-рядку

Проблема: CSV — це не JSON. Передача необробленого CSV-рядка у JSON.parse() викидає SyntaxError, бо коми та символи нового рядка не є валідним синтаксисом JSON.

Рішення: Спочатку розбийте CSV у JavaScript-об'єкти за допомогою split() або бібліотеки, а потім використовуйте JSON.stringify() для отримання JSON. Викликайте JSON.parse() лише для рядків, що вже є валідним JSON.

Before · JavaScript
After · JavaScript
const csv = 'name,email\nОлександр Коваленко,o.kovalenko@nexuslabs.io'
const data = JSON.parse(csv)
// SyntaxError: Unexpected token 'О'
const csv = 'name,email\nОлександр Коваленко,o.kovalenko@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)  // валідний JSON-рядок
Використання toString() замість JSON.stringify()

Проблема: Виклик toString() для JavaScript-об'єкта повертає марний рядок '[object Object]' замість реальних даних. Це непомітно знищує вивід конвертації CSV у JSON.

Рішення: Завжди використовуйте JSON.stringify() для перетворення JavaScript-об'єктів у JSON-рядки. toString() існує для приведення примітивів до рядка, а не для серіалізації.

Before · JavaScript
After · JavaScript
const row = { server: 'api-gateway', port: 8080 }
const output = row.toString()
// "[object Object]"  — дані втрачено
const row = { server: 'api-gateway', port: 8080 }
const output = JSON.stringify(row, null, 2)
// '{"server":"api-gateway","port":8080}'
Розбиття по комі без обробки полів у лапках

Проблема: Наївний split(",") ламається, коли CSV-значення містять коми в полях у лапках: "Widget, Large" стає двома окремими значеннями замість одного.

Рішення: Використовуйте PapaParse або csv-parse для будь-яких CSV-даних, що ви не повністю контролюєте. Якщо необхідно розбирати вручну, реалізуйте парсер зі скінченним автоматом, що відстежує, чи поточна позиція знаходиться всередині поля у лапках.

Before · JavaScript
After · JavaScript
const line = '"Widget, Large","Premium quality",29.99'
const values = line.split(',')
// ["\"Widget", " Large\"", "\"Premium quality\"", "29.99"]
// 4 значення замість 3 — перше поле розбите невірно
import Papa from 'papaparse'
const { data } = Papa.parse('"Widget, Large","Premium quality",29.99')
// data[0] = ["Widget, Large", "Premium quality", "29.99"]
// 3 значення, розбито коректно
Забуття, що всі значення CSV є рядками

Проблема: Без приведення типів port: "8080" залишається рядком у JSON замість числа. Подальші системи, що очікують числові типи, відхиляють або неправильно обробляють дані.

Рішення: Застосовуйте явне приведення типів під час кроку відображення, або використовуйте PapaParse з dynamicTyping: true. Завжди чітко визначайте, які поля мають бути числовими.

Before · JavaScript
After · JavaScript
const row = { port: '8443', debug: 'true', workers: '4' }
JSON.stringify(row)
// {"port":"8443","debug":"true","workers":"4"}  — все рядки
const row = {
  port: Number('8443'),           // 8443
  debug: 'true' === 'true',      // true
  workers: Number('4'),           // 4
}
JSON.stringify(row)
// {"port":8443,"debug":true,"workers":4}  — правильні типи

Ручний розбір проти бібліотек — швидке порівняння

Метод
Форматований вивід
Валідний JSON
Власні типи
Стрімінг
Потребує встановлення
JSON.stringify()
✓ (з space)
✓ через toJSON()/replacer
Ні (вбудований)
JSON.parse()
Н/З (розбір)
✓ (валідує)
✓ через reviver
Ні (вбудований)
csv-parse (Node.js)
✗ (повертає об'єкти)
✗ (не JSON)
npm install
PapaParse
✗ (повертає об'єкти)
✗ (не JSON)
npm install
csvtojson
✓ через colParser
npm install
jq (CLI)
Н/З
Системне встановлення
Miller (CLI)
Н/З
Системне встановлення

Для швидких скриптів, де ви контролюєте формат CSV і знаєте, що в ньому немає полів у лапках, вбудований підхід split() + JSON.stringify() працює і не потребує залежностей. Для виробничих систем, що обробляють завантажені користувачами CSV-файли, використовуйте PapaParse у браузері або csv-parse у Node.js — обидва коректно обробляють RFC 4180 і підтримують потокову передачу. Пакет csvtojson — єдиний, що виводить JSON безпосередньо, обробляючи розбір і серіалізацію в одному виклику. Коли потрібний найшвидший шлях від вставки до результату, конвертер CSV у JSON впорається з усім у браузері без жодного налаштування.

Часті запитання

Як конвертувати CSV у JSON у JavaScript без бібліотеки?

Розбийте CSV-рядок по символу нового рядка, щоб отримати рядки, витягніть заголовки з першого рядка за допомогою split(","), а потім перетворіть решту рядків на об'єкти з ключами з цих заголовків. Завершіть JSON.stringify(array, null, 2) для отримання форматованого JSON-рядка. Цей підхід добре працює для простих CSV-файлів, де ви контролюєте формат і знаєте, що в них немає полів у лапках чи вбудованих ком. Для даних з експортів таблиць або сторонніх систем поля у лапках та багаторядкові значення зламають наївний розбивач — у таких випадках переходьте на PapaParse або csv-parse. Для дуже маленьких файлів, що обробляються у браузері, цей підхід без залежностей є ідеальним.

JavaScript
const csv = `name,email,department
Олександр Коваленко,o.kovalenko@nexuslabs.io,Engineering
Марія Шевченко,m.shevchenko@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": "Олександр Коваленко", "email": "o.kovalenko@nexuslabs.io", "department": "Engineering" },
//   { "name": "Марія Шевченко", "email": "m.shevchenko@nexuslabs.io", "department": "Product" }
// ]

У чому різниця між JSON.stringify() та toString() для об'єктів?

toString() для звичайного об'єкта повертає марний рядок "[object Object]" — він нічого не повідомляє про реальні дані. JSON.stringify() формує валідний JSON-рядок з усіма ключами та значеннями, коректно серіалізованими, включно з вкладеними об'єктами та масивами. Завжди використовуйте JSON.stringify() для перетворення JavaScript-об'єкта (наприклад, рядка з CSV) у JSON-рядок. Щоб виконати зворотну операцію — відновити живі JavaScript-об'єкти з JSON-рядка — використовуйте JSON.parse(), який є точною оберненою функцією до JSON.stringify(). Ці дві функції утворюють повний цикл: stringify для збереження або передачі даних, parse для їх споживання.

JavaScript
const row = { name: 'Олександр Коваленко', role: 'Engineer' }

console.log(row.toString())       // "[object Object]"
console.log(JSON.stringify(row))   // '{"name":"Олександр Коваленко","role":"Engineer"}'

Як обробляти CSV-поля, що містять коми або лапки?

RFC 4180 вказує, що поля, які містять коми, символи нового рядка або подвійні лапки, мають бути загорнуті в подвійні лапки, а вбудовані лапки екрануються подвоєнням ("" всередині поля в лапках позначає одну пряму лапку). Ручний split(",") ламається на таких файлах — межа поля вже не є простою комою. Використовуйте PapaParse або csv-parse для виробничих даних, або напишіть парсер зі скінченним автоматом, який відстежує, чи знаходитеся ви всередині поля в лапках. Написати правильний скінченний автомат з нуля — справа непроста: потрібно обробляти лапки на початку поля, екрановані лапки всередині поля, символи нового рядка в полях у лапках та різні варіанти закінчення рядка (CRLF vs LF). Для будь-яких даних складніших за найпростіший CSV використовуйте добре перевірену бібліотеку.

JavaScript
// PapaParse коректно обробляє RFC 4180
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"

Чи можна конвертувати CSV у JSON безпосередньо у браузері?

Так. JSON.stringify() та JSON.parse() вбудовані у кожен браузерний рушій. Для кроку розбору CSV ви можете розбивати по рядках і комах для простих файлів, або підключити PapaParse через CDN (він не має залежностей від Node.js). Вся конвертація відбувається на стороні клієнта без звернень до сервера, що корисно для конфіденційності файлів — необроблені CSV-дані ніколи не покидають машину користувача. Коли користувач завантажує CSV-файл через елемент <input type="file">, метод file.text() File API повертає Promise, який розв'язується до вмісту файлу у вигляді рядка, і цей рядок можна передати у вашу функцію конвертації. Це робить повністю браузерну конвертацію CSV у JSON практичною для дашбордів, інструментів розробника та будь-яких застосунків, що обробляють завантажені дані без бекенду.

JavaScript
// Браузер: користувач завантажує 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))
})

Як розбирати числові та булеві значення з CSV замість того, щоб залишати все рядками?

У CSV немає системи типів — кожне поле є рядком. Потрібно приводити значення до потрібних типів під час кроку відображення. Перевіряйте числові патерни за допомогою Number() або parseFloat(), перетворюйте "true"/"false" на булеві значення та обробляйте порожні рядки як null. Будьте обережні з полями, що схожі на числа, але мають залишатися рядками: поштові індекси на кшталт "07302" втрачають початковий нуль при перетворенні за допомогою Number(), а телефонні номери або коди продуктів з числовими символами так само крихкі. Бібліотека csvtojson виконує автоматичне приведення типів через опцію colParser, яка дозволяє задавати функції перетворення для кожного стовпця та перекривати автоматичне визначення для проблемних стовпців. Опція dynamicTyping у PapaParse застосовує таке ж приведення глобально для всіх стовпців.

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
}

// Застосовується під час відображення CSV → об'єкт
const row = { port: coerceValue('8443'), debug: coerceValue('true'), host: coerceValue('api.internal') }
// { port: 8443, debug: true, host: "api.internal" }

Як записати результат конвертації CSV у JSON у файл у Node.js?

Використовуйте fs.writeFileSync() з виводом JSON.stringify(). Третій аргумент JSON.stringify керує відступами — передайте 2 для відступу у два пробіли або "\t" для табуляції. Щоб зчитати файл назад, використовуйте JSON.parse(fs.readFileSync(path, "utf8")), що відновлює живий JavaScript-масив об'єктів. Якщо ви записуєте файл в асинхронному контексті (всередині async-функції або на верхньому рівні ES-модуля), надавайте перевагу fs.promises.writeFile(), щоб не блокувати цикл подій під час запису. Для великих JSON-виводів понад кілька мегабайтів розгляньте передавання JSON-потоку у WriteStream замість того, щоб будувати весь рядок у пам'яті перед записом.

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

// Запис
const jsonOutput = JSON.stringify(rows, null, 2)
writeFileSync('employees.json', jsonOutput, 'utf8')

// Зчитування назад
const parsed = JSON.parse(readFileSync('employees.json', 'utf8'))
console.log(Array.isArray(parsed))  // true
console.log(parsed[0].name)         // "Олександр Коваленко"

Пов'язані інструменти

Також доступно на: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 LaurentТехнічний рецензент

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.