CSV to JSON JavaScript โ Converter + Code Examples
Gunakan CSV to JSON gratis langsung di browser Anda โ tidak perlu instalasi.
Coba CSV to JSON Online โSebagian besar data CSV yang saya temui datang sebagai string datar dari unggahan file, ekspor database, atau API yang masih menggunakan format tahun 1970-an. Untuk mengonversi CSV ke JSON di JavaScript, Anda membutuhkan dua hal yang diberikan bahasa secara gratis: pemisahan string untuk mem-parse baris dan JSON.stringify() untuk menserialisasi hasilnya. Tidak diperlukan paket npm untuk hal dasar โ panduan ini mencakup pipeline lengkap dari utilitas csvToJson() yang dapat digunakan kembali hingga PapaParse dan I/O file Node.js. Untuk konversi cepat tanpa kode, the konverter CSV ke JSON online menanganinya secara instan. Semua contoh ditargetkan untuk Node.js 18+ dan browser modern.
- โPisahkan CSV berdasarkan baris baru, ekstrak header dari baris 0, petakan baris yang tersisa ke objek, lalu JSON.stringify(array, null, 2) untuk output yang rapi.
- โJSON.stringify() menghasilkan string; JSON.parse() mengonversinya kembali ke array JavaScript langsung โ ketahui mana yang Anda miliki sebelum mengoperasinya.
- โInstance Map tidak diserialisasi ke JSON secara otomatis โ panggil Object.fromEntries(map) terlebih dahulu.
- โUntuk CSV dengan kolom yang dikutip, koma di dalam nilai, atau baris baru di sel, gunakan PapaParse atau csv-parse daripada pemisahan manual.
- โcsvtojson (npm) menangani konversi tipe, streaming, dan kasus tepi RFC 4180 dalam satu panggilan.
Apa itu Konversi CSV ke JSON?
Konversi CSV ke JSON mengubah format teks datar yang dibatasi koma menjadi array objek terstruktur di mana setiap baris menjadi objek JavaScript yang dikunci oleh header kolom. Format CSV tidak memiliki tipe data โ semuanya adalah string. JSON menambahkan struktur, nesting, dan tipe eksplisit (angka, boolean, null). Konversi ini adalah langkah pertama dalam hampir setiap pipeline data yang dimulai dengan ekspor spreadsheet, dump sistem lama, atau file yang diunggah pengguna. Data yang mendasarinya tetap sama; formatnya berubah dari kolom berbasis posisi menjadi properti bernama.
name,email,role,active Budi Santoso,bsantoso@nexuslabs.io,Engineering Lead,true Sari Dewi,sdewi@nexuslabs.io,Product Manager,true
[
{
"name": "Budi Santoso",
"email": "bsantoso@nexuslabs.io",
"role": "Engineering Lead",
"active": "true"
},
{
"name": "Sari Dewi",
"email": "sdewi@nexuslabs.io",
"role": "Product Manager",
"active": "true"
}
]csvToJson() โ Membangun Fungsi Konversi yang Dapat Digunakan Kembali
Pipeline CSV-ke-JSON lengkap di JavaScript terbagi menjadi tiga langkah: pisahkan string CSV berdasarkan baris baru untuk mendapatkan baris-baris, ekstrak header dari baris pertama dengan split(','), lalu petakan setiap baris yang tersisa ke objek JavaScript biasa di mana key berasal dari header dan nilai berasal dari posisi kolom yang sesuai. Panggilan terakhir ke JSON.stringify() mengonversi array objek tersebut menjadi string JSON. Berikut adalah versi minimal yang berfungsi:
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" }
// ]Fungsi tersebut menangani hal-hal dasar: baris baru di akhir, baris kosong, spasi di sekitar nilai. Setiap kolom CSV melewati sebagai string. Perhatikan bahwa port adalah "8080" (string), bukan 8080 (angka). Jika Anda membutuhkan tipe yang tepat dalam output JSON, Anda harus melakukan konversi sendiri. Berikut versi yang diperluas dengan deteksi tipe:
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 }
// ]Flag coerce bersifat opt-in karena deteksi tipe otomatis bisa memberikan efek yang tidak diinginkan โ kolom seperti kode pos ("07302") kehilangan angka nol di depannya saat dikonversi ke angka. Nonaktifkan konversi secara default dan aktifkan hanya saat Anda mengontrol skema. Catatan singkat: JSON.stringify() menerima argumen ketiga space untuk indentasi. Berikan 2 untuk dua spasi, 4 untuk empat, atau "\t" untuk tab. Hilangkan sama sekali untuk output satu baris yang ringkas โ berguna saat mengirim string JSON sebagai badan permintaan API di mana spasi putih hanya membuang bandwidth.
JSON.parse() langsung pada teks CSV akan melempar SyntaxError. Anda harus terlebih dahulu mengonversi CSV ke objek JavaScript dengan fungsi csvToJson() Anda, yang secara internal memanggil JSON.stringify() untuk menghasilkan string JSON aktual.Menangani Map, Date, dan Objek Kustom dari Data CSV
Tidak setiap konversi CSV berakhir dengan array datar dari objek biasa. Terkadang Anda perlu membangun Map dari pasangan header-nilai, mem-parse string tanggal ke objek Date, atau melampirkan properti yang dihitung sebelum serialisasi. JavaScript memiliki keanehan yang sering membuat orang tersandung: instance Map tidak diserialisasi dengan JSON.stringify(). Anda mendapat objek kosong. Solusinya adalah Object.fromEntries() untuk mengonversi Map kembali ke objek biasa sebelum melakukan stringify.
Alasan Map diserialisasi menjadi {} adalah bahwa JSON.stringify() mengiterasi properti enumerable milik objek sendiri. Map menyimpan entri-entrinya di slot internal, bukan sebagai properti enumerable pada objek itu sendiri, sehingga serializer melihat objek tanpa key. Prototipe Map juga tidak memiliki metode toJSON(), yang merupakan hook yang dipanggil JSON.stringify() pertama kali pada nilai apa pun sebelum memutuskan cara menserialisasinya. Jika nilai memiliki toJSON(), nilai kembalian metode itulah yang diserialisasi โ bukan objeknya sendiri. Inilah mengapa objek Date diserialisasi dengan benar: Date.prototype.toJSON mengembalikan string ISO 8601, sehingga JSON.stringify(new Date()) menghasilkan timestamp yang dikutip daripada objek kosong. Memahami hook ini memungkinkan Anda mendefinisikan perilaku yang sama pada kelas Anda sendiri โ seperti yang ditunjukkan dalam contoh EmployeeRecord di bawah โ untuk mengontrol persis kolom CSV mana yang muncul dalam output JSON akhir.
Mengonversi Map ke JSON
// Bangun Map dari pasangan headerโnilai 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 TIDAK diserialisasi langsung
console.log(JSON.stringify(rowMap))
// "{}" โ objek kosong, data hilang!
// Konversi ke objek biasa terlebih dahulu
const rowObj = Object.fromEntries(rowMap)
console.log(JSON.stringify(rowObj, null, 2))
// {
// "server": "payments-api",
// "port": "9090",
// "region": "ap-south-1"
// }String Tanggal dan toJSON()
Kolom tanggal CSV datang sebagai string. Jika Anda mem-parse-nya ke objek Date selama pemrosesan, Date tersebut diserialisasi dengan benar karena Date memiliki metode toJSON() bawaan yang mengembalikan string ISO 8601. Anda juga dapat mendefinisikan toJSON() kustom pada kelas Anda sendiri untuk mengontrol kolom CSV mana yang muncul dalam output yang diserialisasi โ misalnya, menghilangkan kolom pelacakan internal seperti _rowIndex.
class EmployeeRecord {
constructor(csvRow) {
this._rowIndex = csvRow._rowIndex // internal, bukan untuk JSON
this.employeeId = csvRow.employee_id
this.name = csvRow.name
this.hiredAt = new Date(csvRow.hired_date)
this.salary = Number(csvRow.salary)
}
toJSON() {
// Hanya tampilkan kolom yang ingin ada dalam output JSON
return {
employee_id: this.employeeId,
name: this.name,
hired_at: this.hiredAt, // Date.toJSON() โ string ISO secara otomatis
salary: this.salary,
}
}
}
const csvRow = {
_rowIndex: 42,
employee_id: 'EMP-2847',
name: 'Budi Santoso',
hired_date: '2024-03-15',
salary: '128000',
}
const record = new EmployeeRecord(csvRow)
console.log(JSON.stringify(record, null, 2))
// {
// "employee_id": "EMP-2847",
// "name": "Budi Santoso",
// "hired_at": "2024-03-15T00:00:00.000Z",
// "salary": 128000
// }
// Catatan: _rowIndex dikecualikan, salary adalah angka, tanggal dalam format ISOReviver untuk Deserialisasi Date
Setelah menulis JSON yang berasal dari CSV ke file atau mengirimkannya melalui jaringan, JSON.parse() mengembalikan objek biasa โ objek Date menjadi string lagi. Gunakan fungsi reviver untuk mengonversi string ISO 8601 kembali ke objek Date selama parsing:
const jsonString = '{"employee_id":"EMP-2847","name":"Budi Santoso","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()) // 2024JSON.stringify() mengembalikan undefined (bukan string) untuk nilai yang mengandung fungsi, Symbol, atau properti undefined. Jika objek yang berasal dari CSV Anda secara tidak sengaja mengambil nilai undefined dari kolom yang hilang, properti tersebut hilang secara diam-diam dari output JSON. Selalu gunakan null sebagai default untuk nilai yang hilang.Referensi Parameter JSON.stringify()
Tanda tangan fungsinya adalah JSON.stringify(value, replacer?, space?). Argumen replacer dan space keduanya opsional โ berikan null untuk replacer saat Anda hanya membutuhkan indentasi.
Parameter JSON.parse():
JSON.parse() โ Menggunakan Output JSON
Setelah Anda memiliki string JSON dari csvToJson(), langkah berikutnya biasanya adalah mem-parse-nya kembali ke array JavaScript langsung untuk filtering, mapping, atau mengirimkannya ke API. Perbedaan antara string JSON (typeof === "string") dan objek JavaScript itu penting. Anda tidak dapat memanggil .filter() atau mengakses [0].name pada string โ Anda membutuhkan JSON.parse() terlebih dahulu. Perjalanan pulang-pergi ini (stringify lalu parse) juga berfungsi sebagai teknik validasi: jika konversi CSV Anda menghasilkan sesuatu yang bukan JSON valid, parse akan melempar. Argumen reviver opsional memungkinkan Anda mengubah setiap pasangan key-value selama parsing โ berguna untuk memulihkan objek Date dari string ISO atau mengganti nama key tanpa proses terpisah.
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`
// Langkah 1: konversi CSV ke string JSON
const jsonString = csvToJson(csv, { coerce: true })
// Langkah 2: parse kembali ke array JavaScript
const endpoints = JSON.parse(jsonString)
// Verifikasi bahwa ini adalah array
console.log(Array.isArray(endpoints)) // true
// Filter endpoint dengan latensi tinggi
const slow = endpoints.filter(ep => ep.avg_latency_ms > 200)
console.log(slow.map(ep => ep.endpoint))
// ["/api/v2/orders", "/api/v2/payments"]
// Destrukturisasi baris pertama
const [first, ...rest] = endpoints
console.log(first.endpoint) // "/api/v2/orders"
console.log(rest.length) // 3Wrapper yang aman untuk JSON.parse() berguna saat memvalidasi output konversi sebelum pemrosesan lebih lanjut. Jika konversi CSV menghasilkan JSON yang cacat karena alasan apa pun (input yang terpotong, kesalahan encoding), ini menangkapnya tanpa crash:
function safeParse(jsonString) {
try {
return { data: JSON.parse(jsonString), error: null }
} catch (err) {
return { data: null, error: err.message }
}
}
// Output valid
const result = safeParse(csvToJson(csv))
if (result.error) {
console.error('Konversi CSV menghasilkan JSON tidak valid:', result.error)
} else {
console.log(`Parsed ${result.data.length} baris`)
}
// Secara tidak sengaja meneruskan CSV mentah ke JSON.parse โ ini gagal
const bad = safeParse('name,email\nBudi,bsantoso@nexuslabs.io')
console.log(bad.error) // "Unexpected token 'a', "name,email"... is not valid JSON"Reviver untuk Penggantian Nama Key dan Validasi
Fungsi reviver menerima setiap pasangan key-value selama parsing, dari properti paling dalam ke luar. Mengembalikan undefined untuk sebuah key menghapusnya dari hasil sepenuhnya; mengembalikan nilai yang berbeda menggantinya. Reviver berguna untuk mengganti nama header (camelCase ke snake_case), menghapus kolom internal, atau memeriksa apakah kolom yang diperlukan ada. Ia dipanggil dengan nilai root terakhir (key string kosong), di mana Anda melempar jika hasilnya bukan array.
const jsonString = csvToJson(`employeeId,firstName,hiredDate
EMP-2847,Budi,2024-03-15
EMP-3012,Sari,2023-11-01`, { coerce: false })
const camelToSnake = str => str.replace(/[A-Z]/g, c => '_' + c.toLowerCase())
const employees = JSON.parse(jsonString, function(key, value) {
// Nilai root โ validasi bentuk
if (key === '') {
if (!Array.isArray(value)) throw new Error('Diharapkan array JSON dari CSV')
return value
}
// Ganti nama key header camelCase ke 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: 'Budi', hired_date: '2024-03-15' }Mengonversi CSV dari File dan Respons API
Dua tempat data CSV sebenarnya berasal dalam produksi: file di disk dan respons HTTP. Kedua skenario memerlukan penanganan error karena input berasal dari luar dan tidak terkontrol.
Baca File CSV, Konversi, Tulis JSON
import { readFileSync, writeFileSync } from 'node:fs'
function csvToJsonFromFile(inputPath, outputPath) {
let csvText
try {
csvText = readFileSync(inputPath, 'utf8')
} catch (err) {
throw new Error(`Gagal membaca ${inputPath}: ${err.message}`)
}
const lines = csvText.trim().split('\n')
if (lines.length < 2) {
throw new Error(`${inputPath} tidak memiliki baris data (hanya ${lines.length} baris)`)
}
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(`Mengonversi ${rows.length} baris โ ${outputPath}`)
return rows
}
// Penggunaan
const data = csvToJsonFromFile('inventory.csv', 'inventory.json')
console.log(data[0])
// { sku: "WDG-2847", warehouse: "us-east-1", quantity: "150", ... }Ambil CSV dari Endpoint 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 tidak terduga: ${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
}
// Contoh: ambil CSV nilai tukar dari penyedia data
try {
const rates = await fetchCsvAsJson('https://data.ecb.internal/rates/daily.csv')
console.log(JSON.stringify(rates.slice(0, 3), null, 2))
// Kirim sebagai JSON ke layanan hilir
await fetch('https://api.internal/v2/rates', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ data: rates }),
})
} catch (err) {
console.error('Sinkronisasi nilai tukar gagal:', err.message)
}JSON.stringify() memungkinkan Anda membatasi kolom tertentu dari CSV. Berikan array nama header untuk hanya menyertakan kolom tersebut: JSON.stringify(rows, ['name', 'email', 'department']). Properti yang tidak ada dalam array dikecualikan secara diam-diam dari output.Konversi CSV ke JSON via Command-Line
Node.js dapat menjalankan skrip inline, dan ada alat CLI khusus yang menangani konversi CSV-ke-JSON tanpa menulis skrip.
# Pipe CSV ke skrip inline 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));
"# Miller adalah pisau Swiss Army untuk data terstruktur # Install: brew install miller (macOS) atau apt install miller (Debian/Ubuntu) mlr --icsv --ojson cat inventory.csv # Filter baris selama konversi mlr --icsv --ojson filter '$quantity > 100' inventory.csv # Pilih kolom tertentu mlr --icsv --ojson cut -f sku,warehouse,quantity inventory.csv
# Install secara global npm install -g csvtojson # Konversi file csvtojson servers.csv > servers.json # Pipe dari stdin cat exports/q1-metrics.csv | csvtojson > q1-metrics.json
Untuk file besar, Miller biasanya merupakan pilihan yang lebih baik daripada csvtojson. Miller diimplementasikan dalam C dan memproses CSV sebagai stream tanpa memuat seluruh file ke dalam memori, yang berarti ia menangani ekspor multi-gigabyte dengan penggunaan memori yang konstan. Ia juga mendukung operasi tingkat kolom di tempat โ mengganti nama kolom, mengkonversi tipe nilai, memfilter baris โ sebelum data menjadi JSON, sehingga Anda menghindari pipeline parse-lalu-transform dua langkah. csvtojson, di sisi lain, berjalan di Node.js dan lebih mudah digunakan saat toolchain Anda yang lain adalah JavaScript: Anda dapat mem-pipe outputnya langsung ke stream Node, mengimpornya sebagai library, atau menggunakan API colParser-nyauntuk konversi tipe per kolom dalam kode. Gunakan Miller untuk throughput mentah dan pipeline shell; gunakan csvtojson saat Anda membutuhkan integrasi erat dengan aplikasi Node.js.
jq tidak mem-parse CSV secara native. Jika Anda membutuhkan jq dalam pipeline, konversi ke JSON terlebih dahulu dengan csvtojson atau mlr, lalu pipe output JSON ke jq untuk filtering dan transformasi.Alternatif Berkinerja Tinggi โ PapaParse
Pendekatan manual split(',') gagal pada file CSV dunia nyata. Kolom yang dikutip yang mengandung koma, baris baru yang tertanam, tanda kutip ganda yang di-escape โ semua ini merusak pemisah naif. PapaParse adalah library yang saya gunakan ketika CSV berasal dari sumber yang tidak diketahui. Ia menangani setiap kasus tepi RFC 4180, mendeteksi delimiter secara otomatis, dan bekerja di Node.js dan browser.
npm install 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, // otomatis mengonversi angka dan boolean
skipEmptyLines: true,
transformHeader: h => h.trim().toLowerCase().replace(/\s+/g, '_'),
})
if (errors.length > 0) {
console.error('Error parsing:', 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} baris, delimiter: "${meta.delimiter}"`)Opsi dynamicTyping PapaParse melakukan konversi tipe secara otomatis โ angka menjadi angka, "true"/"false" menjadi boolean. Callback transformHeader menormalkan nama kolom ke snake_case, yang menghemat Anda dari berurusan dengan header yang tidak konsisten dari ekspor CSV yang berbeda. Untuk konversi cepat tanpa menulis kode parsing apa pun, the konverter CSV ke JSON menangani semua ini di browser.
Output Terminal dengan Syntax Highlighting
Membuang array JSON besar ke terminal membuat mata cepat lelah. Menambahkan syntax highlighting ke output membuatnya mudah dibaca selama debugging dan pengembangan. Paket cli-highlight mewarnai output JSON di terminal Node.js.
npm install cli-highlight
import { highlight } from 'cli-highlight'
// Setelah mengonversi CSV ke array JSON
const jsonOutput = JSON.stringify(rows, null, 2)
// Cetak dengan syntax highlighting
console.log(highlight(jsonOutput, { language: 'json' }))
// Key, string, angka, dan boolean masing-masing mendapat warna berbedaOutput berwarna sangat berguna saat Anda memeriksa hasil konversi besar secara interaktif. Key JSON, nilai string, angka, dan boolean masing-masing mendapat warna ANSI berbeda, yang memudahkan untuk menemukan kolom yang tipenya salah โ misalnya, nomor port yang seharusnya 8080 tetapi disorot sebagai string karena konversi dinonaktifkan. Ini sangat berguna saat men-debug file CSV yang diekspor dari alat spreadsheet di mana tipe kolom tidak konsisten di seluruh baris. Tanpa warna, memindai 50 baris JSON untuk satu kolom yang salah tipe berarti membaca setiap nilai satu per satu. Dengan warna, angka berwarna string langsung terlihat.
Bekerja dengan File CSV Besar
Memuat file CSV 500 MB ke dalam string dengan readFileSync() akan menghabiskan memori dan berpotensi mematikan proses Anda. Untuk file besar, stream CSV baris per baris dan emit objek JSON saat datang. Paket csv-parse (bagian dari ekosistem csv di npm) menyediakan parser streaming yang bekerja dengan stream Node.js.
Streaming CSV ke NDJSON dengan csv-parse
NDJSON (Newline-Delimited JSON) adalah format di mana setiap baris file output adalah objek JSON yang mandiri. Tidak seperti array JSON besar tunggal โ yang memerlukan seluruh file ada di memori sebelum Anda dapat mulai membacanya โ file NDJSON dapat diproses baris per baris. Ini membuat NDJSON ideal untuk dataset besar yang akan dikonsumsi oleh prosesor log, pipeline stream, atau database dengan API bulk-import. Paket csv-parse memancarkan satu objek JavaScript per baris CSV dalam mode objek, sehingga Anda dapat mem-pipe-nya langsung ke transform stream yang menambahkan \n setelah setiap JSON.stringify(row).
import { createReadStream, createWriteStream } from 'node:fs'
import { parse } from 'csv-parse'
import { Transform } from 'node:stream'
import { pipeline } from 'node:stream/promises'
// Transformasi setiap objek baris CSV ke baris 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, // gunakan baris pertama sebagai header
skip_empty_lines: true,
trim: true,
cast: true, // otomatis konversi angka dan boolean
}),
toNdjson,
createWriteStream('telemetry-2026-03.ndjson')
)
console.log('Konversi streaming selesai')
// Setiap baris dalam file output adalah satu objek 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 Streaming untuk Browser dan Node.js
Mode streaming PapaParse menggunakan callback step yang dipicu sekali per baris daripada mengumpulkan semua baris di memori. Anda meneruskan ReadStream Node.js (di Node.js) atau objek File (di browser) dan PapaParse menangani chunking secara internal. Tidak ada pipeline stream yang perlu dikonfigurasi โ cukup sebuah callback. Gunakan saat Anda membutuhkan kepatuhan RFC 4180 tanpa menarik csv-parse.
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) {
// Proses satu baris sekaligus โ memori konstan
rowCount++
if (result.data.quantity === 0) {
errors.push(`Baris ${rowCount}: ${result.data.sku} kehabisan stok`)
}
},
complete() {
console.log(`Memproses ${rowCount} baris`)
if (errors.length > 0) {
console.log(`Masalah ditemukan: ${errors.length}`)
errors.forEach(e => console.log(` ${e}`))
}
},
error(err) {
console.error('Parsing gagal:', err.message)
},
})Kesalahan Umum
Masalah: CSV bukan JSON. Meneruskan string CSV mentah ke JSON.parse() melempar SyntaxError karena koma dan baris baru bukan sintaks JSON yang valid.
Solusi: Parse CSV ke objek JavaScript terlebih dahulu menggunakan split() atau library, lalu gunakan JSON.stringify() untuk menghasilkan JSON. Hanya panggil JSON.parse() pada string yang sudah berupa JSON valid.
const csv = 'name,email\nBudi Santoso,bsantoso@nexuslabs.io' const data = JSON.parse(csv) // SyntaxError: Unexpected token 'a'
const csv = 'name,email\nBudi Santoso,bsantoso@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) // string JSON validMasalah: Memanggil toString() pada objek JavaScript mengembalikan string yang tidak berguna '[object Object]' daripada data aktual. Ini diam-diam merusak output CSV-ke-JSON Anda.
Solusi: Selalu gunakan JSON.stringify() untuk mengonversi objek JavaScript ke string JSON. toString() ada untuk konversi primitif-ke-string, bukan untuk serialisasi.
const row = { server: 'api-gateway', port: 8080 }
const output = row.toString()
// "[object Object]" โ data hilangconst row = { server: 'api-gateway', port: 8080 }
const output = JSON.stringify(row, null, 2)
// '{"server":"api-gateway","port":8080}'Masalah: Pemisahan naif split(",") rusak ketika nilai CSV mengandung koma di dalam kolom yang dikutip: "Widget, Large" menjadi dua nilai terpisah alih-alih satu.
Solusi: Gunakan PapaParse atau csv-parse untuk data CSV apa pun yang tidak sepenuhnya Anda kontrol. Jika Anda harus mem-parse secara manual, implementasikan parser state-machine yang melacak apakah posisi saat ini berada di dalam kolom yang dikutip.
const line = '"Widget, Large","Premium quality",29.99'
const values = line.split(',')
// ["\"Widget", " Large\"", "\"Premium quality\"", "29.99"]
// 4 nilai alih-alih 3 โ kolom pertama dipisah secara tidak benarimport Papa from 'papaparse'
const { data } = Papa.parse('"Widget, Large","Premium quality",29.99')
// data[0] = ["Widget, Large", "Premium quality", "29.99"]
// 3 nilai, diparsing dengan benarMasalah: Tanpa konversi tipe, port: "8080" tetap sebagai string dalam JSON alih-alih angka. Sistem hilir yang mengharapkan tipe numerik menolak atau menangani data secara salah.
Solusi: Terapkan konversi tipe eksplisit selama langkah pemetaan, atau gunakan PapaParse dengan dynamicTyping: true. Selalu sengaja tentang kolom mana yang harus numerik.
const row = { port: '8443', debug: 'true', workers: '4' }
JSON.stringify(row)
// {"port":"8443","debug":"true","workers":"4"} โ semua stringconst row = {
port: Number('8443'), // 8443
debug: 'true' === 'true', // true
workers: Number('4'), // 4
}
JSON.stringify(row)
// {"port":8443,"debug":true,"workers":4} โ tipe yang benarParsing Manual vs Library โ Perbandingan Singkat
Untuk skrip cepat di mana Anda mengontrol format CSV dan tahu tidak ada kolom yang dikutip, pendekatan bawaan split() + JSON.stringify() berfungsi dan memerlukan nol dependensi. Untuk sistem produksi yang memproses file CSV yang diunggah pengguna, gunakan PapaParse di browser atau csv-parse di Node.js โ keduanya menangani RFC 4180 dengan benar dan mendukung streaming. Paket csvtojson adalah satu-satunya yang menghasilkan JSON langsung, menangani parsing dan serialisasi dalam satu panggilan. Saat Anda membutuhkan jalur tercepat dari tempel-ke-hasil, the konverter CSV ke JSON menangani semuanya di browser tanpa setup apa pun.
Pertanyaan yang Sering Diajukan
Bagaimana cara mengonversi CSV ke JSON di JavaScript tanpa library?
Pisahkan string CSV berdasarkan baris baru untuk mendapatkan baris-baris data, ekstrak header dari baris pertama dengan split(","), lalu petakan baris yang tersisa ke objek yang dikunci oleh header tersebut. Selesaikan dengan JSON.stringify(array, null, 2) untuk menghasilkan string JSON yang terformat. Pendekatan ini cocok untuk file CSV sederhana di mana Anda mengontrol formatnya dan tahu tidak ada kolom yang dikutip atau koma di dalam nilai. Untuk data dari ekspor spreadsheet atau sistem pihak ketiga, kolom yang dikutip dan nilai multi-baris akan merusak pemisah naif โ gunakan PapaParse atau csv-parse dalam kasus tersebut. Untuk file yang sangat kecil yang diproses di browser, pendekatan tanpa dependensi ini sangat ideal.
const csv = `name,email,department
Budi Santoso,bsantoso@nexuslabs.io,Engineering
Sari Dewi,sdewi@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": "Budi Santoso", "email": "bsantoso@nexuslabs.io", "department": "Engineering" },
// { "name": "Sari Dewi", "email": "sdewi@nexuslabs.io", "department": "Product" }
// ]Apa perbedaan antara JSON.stringify() dan toString() untuk objek?
toString() pada objek biasa mengembalikan string yang tidak berguna "[object Object]" โ tidak memberikan informasi apapun tentang data aktualnya. JSON.stringify() menghasilkan string JSON yang valid dengan semua key dan value yang diserialisasi dengan benar, termasuk objek dan array yang bersarang. Selalu gunakan JSON.stringify() ketika Anda perlu mengonversi objek JavaScript (seperti baris yang berasal dari CSV) ke string JSON. Untuk membalik operasi โ merekonstruksi objek JavaScript langsung dari string JSON โ gunakan JSON.parse(), yang merupakan kebalikan tepat dari JSON.stringify(). Kedua fungsi ini membentuk perjalanan pulang-pergi yang lengkap: stringify untuk menyimpan atau mengirim data, parse untuk menggunakannya.
const row = { name: 'Budi Santoso', role: 'Engineer' }
console.log(row.toString()) // "[object Object]"
console.log(JSON.stringify(row)) // '{"name":"Budi Santoso","role":"Engineer"}'Bagaimana cara menangani kolom CSV yang mengandung koma atau tanda kutip?
RFC 4180 menetapkan bahwa kolom yang mengandung koma, baris baru, atau tanda kutip ganda harus dibungkus dalam tanda kutip ganda, dengan tanda kutip di dalamnya di-escape dengan cara menggandakannya ("" di dalam kolom yang dikutip mewakili satu tanda kutip literal). Pemisahan manual dengan split(",") tidak berfungsi pada file seperti ini โ batas kolom bukan lagi koma biasa. Gunakan PapaParse atau csv-parse untuk data produksi, atau tulis parser state-machine yang melacak apakah Anda berada di dalam kolom yang dikutip. Menulis state machine yang benar dari awal ternyata cukup rumit: Anda harus menangani tanda kutip di awal kolom, tanda kutip di-escape di tengah kolom, baris baru di dalam kolom yang dikutip, dan konvensi akhir baris yang berbeda (CRLF vs LF). Untuk data CSV apa pun di luar data mainan, gunakan library yang telah teruji.
// PapaParse menangani RFC 4180 dengan benar
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))
// kolom description berisi dengan benar: A big "widget"Bisakah saya mengonversi CSV ke JSON langsung di browser?
Ya. Baik JSON.stringify() maupun JSON.parse() sudah tersedia di setiap mesin browser. Untuk langkah parsing CSV, Anda dapat memisahkan berdasarkan baris baru dan koma untuk file sederhana, atau menyertakan PapaParse melalui CDN (tidak memiliki dependensi Node.js). Seluruh konversi terjadi di sisi klien tanpa perjalanan bolak-balik ke server, yang berguna untuk privasi file โ data CSV mentah tidak pernah meninggalkan mesin pengguna. Ketika pengguna mengunggah file CSV melalui elemen <input type="file">, metode file.text() dari File API mengembalikan Promise yang diselesaikan ke konten file sebagai string, yang kemudian dapat Anda teruskan ke fungsi konversi. Ini membuat konversi CSV-ke-JSON sepenuhnya di browser menjadi praktis untuk dasbor, alat pengembang, dan aplikasi apa pun yang perlu memproses data yang diunggah tanpa backend.
// Browser: pengguna mengunggah file 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))
})Bagaimana cara mem-parse nilai numerik dan boolean dari CSV alih-alih menyimpan semuanya sebagai string?
CSV tidak memiliki sistem tipe โ setiap kolom adalah string. Anda harus memaksa konversi nilai selama langkah pemetaan. Periksa pola numerik dengan Number() atau parseFloat(), konversi "true"/"false" ke boolean, dan tangani string kosong sebagai null. Berhati-hatilah dengan kolom yang terlihat seperti angka tetapi harus tetap sebagai string: kode pos seperti "07302" kehilangan angka nol di depannya saat dipaksa dengan Number(), dan nomor telepon atau kode produk dengan karakter numerik juga sama rapuhnya. Library csvtojson melakukan konversi tipe otomatis melalui opsi colParser-nya, yang memungkinkan Anda menentukan fungsi konversi per kolom dan mengganti deteksi otomatis untuk kolom yang bermasalah. Opsi dynamicTyping PapaParse menerapkan konversi yang sama secara global di semua kolom.
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
}
// Terapkan selama pemetaan CSV ke objek
const row = { port: coerceValue('8443'), debug: coerceValue('true'), host: coerceValue('api.internal') }
// { port: 8443, debug: true, host: "api.internal" }Bagaimana cara menulis output CSV-ke-JSON ke file di Node.js?
Gunakan fs.writeFileSync() dengan output JSON.stringify(). Argumen ketiga untuk JSON.stringify mengontrol indentasi โ berikan 2 untuk indentasi dua spasi atau "\t" untuk tab. Untuk membaca file kembali, gunakan JSON.parse(fs.readFileSync(path, "utf8")), yang merekonstruksi array JavaScript langsung dari objek. Jika Anda menulis file dalam konteks async (di dalam fungsi async atau di level atas modul ES), gunakan fs.promises.writeFile() untuk menghindari pemblokiran event loop selama penulisan file selesai. Untuk output JSON yang besar lebih dari beberapa megabyte, pertimbangkan untuk mem-pipe stream JSON ke WriteStream daripada membangun seluruh string di memori sebelum menulis.
import { writeFileSync, readFileSync } from 'node:fs'
// Tulis
const jsonOutput = JSON.stringify(rows, null, 2)
writeFileSync('karyawan.json', jsonOutput, 'utf8')
// Baca kembali
const parsed = JSON.parse(readFileSync('karyawan.json', 'utf8'))
console.log(Array.isArray(parsed)) // true
console.log(parsed[0].name) // "Budi Santoso"Alat Terkait
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.
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.