CSV to JSON JavaScript — Converter + Code Examples
Use o CSV to JSON gratuito diretamente no seu navegador — sem instalação.
Experimentar CSV to JSON online →A maioria dos dados CSV que encontro chega como uma string plana de um upload de arquivo, uma exportação de banco de dados ou uma API que ainda fala o formato dos anos 1970. Para converter CSV para JSON em JavaScript, você precisa de duas coisas que a linguagem oferece gratuitamente: divisão de strings para analisar as linhas e JSON.stringify() para serializar o resultado. Nenhum pacote npm é necessário para o básico — este guia cobre o pipeline completo, de uma função utilitária reutilizável csvToJson() até PapaParse e E/S de arquivos no Node.js. Para conversões rápidas sem código, o conversor online de CSV para JSON resolve na hora. Todos os exemplos são voltados para Node.js 18+ e navegadores modernos.
- ✓Divida o CSV por quebra de linha, extraia os cabeçalhos da linha 0, mapeie as demais linhas para objetos e use JSON.stringify(array, null, 2) para saída formatada.
- ✓JSON.stringify() produz uma string; JSON.parse() a converte de volta em um array JavaScript vivo — saiba qual você tem antes de operar sobre ele.
- ✓Instâncias de Map não serializam para JSON automaticamente — chame Object.fromEntries(map) primeiro.
- ✓Para CSV com campos entre aspas, vírgulas dentro de valores ou quebras de linha em células, use PapaParse ou csv-parse em vez de divisão manual.
- ✓csvtojson (npm) trata coerção de tipos, streaming e casos extremos da RFC 4180 em uma única chamada.
O que é a Conversão de CSV para JSON?
A conversão de CSV para JSON transforma um formato de texto plano delimitado por vírgulas em um array estruturado de objetos, onde cada linha se torna um objeto JavaScript com chaves provenientes dos cabeçalhos das colunas. O formato CSV não tem tipos de dados — tudo é uma string. JSON adiciona estrutura, aninhamento e tipos explícitos (números, booleanos, null). Essa conversão é o primeiro passo em quase todo pipeline de dados que começa com uma exportação de planilha, um dump de sistema legado ou um arquivo enviado pelo usuário. Os dados subjacentes permanecem os mesmos; o formato muda de colunas baseadas em posição para propriedades nomeadas.
nome,email,cargo,ativo João Silva,jsilva@nexuslabs.io,Líder de Engenharia,true Camila Rocha,crocha@nexuslabs.io,Gerente de Produto,true
[
{
"nome": "João Silva",
"email": "jsilva@nexuslabs.io",
"cargo": "Líder de Engenharia",
"ativo": "true"
},
{
"nome": "Camila Rocha",
"email": "crocha@nexuslabs.io",
"cargo": "Gerente de Produto",
"ativo": "true"
}
]csvToJson() — Construindo uma Função de Conversão Reutilizável
O pipeline completo de CSV para JSON em JavaScript se divide em três etapas: divida a string CSV por quebra de linha para obter as linhas, extraia os cabeçalhos da primeira linha com split(','), depois mapeie cada linha restante para um objeto JavaScript simples onde as chaves vêm dos cabeçalhos e os valores vêm das posições de coluna correspondentes. A chamada final para JSON.stringify() converte esse array de objetos em uma string JSON. Aqui está uma versão mínima funcional:
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 = `servidor,porta,regiao,status
api-gateway,8080,us-east-1,saudavel
auth-service,8443,eu-west-1,degradado
payments-api,9090,ap-south-1,saudavel`
console.log(csvToJson(csv))
// [
// { "servidor": "api-gateway", "porta": "8080", "regiao": "us-east-1", "status": "saudavel" },
// { "servidor": "auth-service", "porta": "8443", "regiao": "eu-west-1", "status": "degradado" },
// { "servidor": "payments-api", "porta": "9090", "regiao": "ap-south-1", "status": "saudavel" }
// ]Essa função trata o básico: quebras de linha no final, linhas vazias, espaços em branco ao redor dos valores. Todo campo CSV chega como uma string. Note que porta é "8080" (uma string), não 8080 (um número). Se você precisar de tipos corretos na saída JSON, é necessário converter você mesmo. Aqui está uma versão estendida com detecção de tipos:
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,porta,max_conexoes,debug
/api/v2/pedidos,8443,500,true
/api/v2/saude,8080,100,false`
console.log(csvToJson(csv, { coerce: true }))
// [
// { "endpoint": "/api/v2/pedidos", "porta": 8443, "max_conexoes": 500, "debug": true },
// { "endpoint": "/api/v2/saude", "porta": 8080, "max_conexoes": 100, "debug": false }
// ]O flag coerce é opt-in porque a detecção automática de tipos pode sair pela culatra — um campo como CEP ("01310-100") perde seu formato ao ser convertido para número. Mantenha a coerção desativada por padrão e ative-a apenas quando você controla o esquema. Nota rápida: JSON.stringify() aceita um terceiro argumento space para indentação. Passe 2 para dois espaços, 4 para quatro, ou "\t" para tabulações. Omita completamente para saída compacta em linha única — útil ao enviar a string JSON como corpo de uma requisição de API, onde espaços em branco apenas desperdiçam largura de banda.
JSON.parse() diretamente em texto CSV lança um SyntaxError. Você deve primeiro converter o CSV em objetos JavaScript com sua função csvToJson(), que internamente chama JSON.stringify() para produzir a string JSON de verdade.Tratando Maps, Datas e Objetos Personalizados de Dados CSV
Nem toda conversão de CSV termina com um array plano de objetos simples. Às vezes você precisa construir um Map a partir de pares cabeçalho-valor, analisar strings de data em objetos Date ou adicionar propriedades calculadas antes da serialização. JavaScript tem uma peculiaridade que pega as pessoas de surpresa: instâncias de Map não serializam com JSON.stringify(). Você obtém um objeto vazio. A solução é Object.fromEntries() para converter o Map de volta para um objeto simples antes de serializar.
O motivo pelo qual Map serializa para {} é que JSON.stringify() itera sobre as próprias propriedades enumeráveis de um objeto. Um Map armazena suas entradas em um slot interno, não como propriedades enumeráveis no próprio objeto, então o serializador vê um objeto sem chaves. O protótipo de Map também não possui um método toJSON(), que é o gancho que JSON.stringify() chama primeiro em qualquer valor antes de decidir como serializá-lo. Se um valor tem toJSON(), o valor retornado pelo método é o que fica serializado — não o próprio objeto. É por isso que Date serializa corretamente: Date.prototype.toJSON retorna uma string ISO 8601, então JSON.stringify(new Date()) produz um timestamp entre aspas em vez de um objeto vazio. Entender esse gancho permite definir o mesmo comportamento em suas próprias classes — como mostrado no exemplo EmployeeRecord abaixo — para controlar exatamente quais campos derivados do CSV aparecem na saída JSON final.
Convertendo um Map para JSON
// Construir um Map a partir de pares cabeçalho→valor do CSV
const headers = ['servidor', 'porta', 'regiao']
const values = ['payments-api', '9090', 'ap-south-1']
const rowMap = new Map(headers.map((h, i) => [h, values[i]]))
// Map NÃO serializa diretamente
console.log(JSON.stringify(rowMap))
// "{}" — objeto vazio, dados perdidos!
// Converter para objeto simples primeiro
const rowObj = Object.fromEntries(rowMap)
console.log(JSON.stringify(rowObj, null, 2))
// {
// "servidor": "payments-api",
// "porta": "9090",
// "regiao": "ap-south-1"
// }Strings de Data e toJSON()
Campos de data no CSV chegam como strings. Se você os converte em objetos Date durante o processamento, esses Dates serializam corretamente porque Date tem um método toJSON() nativo que retorna uma string ISO 8601. Você também pode definir toJSON() personalizado em suas próprias classes para controlar quais colunas CSV aparecem na saída serializada — por exemplo, omitindo campos de rastreamento interno como _rowIndex.
class EmployeeRecord {
constructor(csvRow) {
this._rowIndex = csvRow._rowIndex // interno, não vai para JSON
this.employeeId = csvRow.employee_id
this.name = csvRow.name
this.hiredAt = new Date(csvRow.hired_date)
this.salary = Number(csvRow.salary)
}
toJSON() {
// Expor apenas os campos que queremos na saída JSON
return {
employee_id: this.employeeId,
name: this.name,
hired_at: this.hiredAt, // Date.toJSON() → string ISO automaticamente
salary: this.salary,
}
}
}
const csvRow = {
_rowIndex: 42,
employee_id: 'EMP-2847',
name: 'João Silva',
hired_date: '2024-03-15',
salary: '128000',
}
const record = new EmployeeRecord(csvRow)
console.log(JSON.stringify(record, null, 2))
// {
// "employee_id": "EMP-2847",
// "name": "João Silva",
// "hired_at": "2024-03-15T00:00:00.000Z",
// "salary": 128000
// }
// Nota: _rowIndex é excluído, salary é número, data está em formato ISOReviver para Desserialização de Datas
Após gravar JSON derivado de CSV em um arquivo ou enviá-lo pela rede, JSON.parse() retorna objetos simples — os objetos Date voltam a ser strings. Use uma função reviver para converter strings ISO 8601 de volta em objetos Date durante a análise:
const jsonString = '{"employee_id":"EMP-2847","name":"João Silva","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() retorna undefined (não uma string) para valores que contêm funções, Symbols ou propriedades undefined. Se seus objetos derivados de CSV capturarem acidentalmente um valor undefined de uma coluna ausente, essa propriedade desaparece silenciosamente da saída JSON. Use sempre null como padrão para valores ausentes.Referência de Parâmetros de JSON.stringify()
A assinatura da função é JSON.stringify(value, replacer?, space?). Os argumentos replacer e space são opcionais — passe null para o replacer quando precisar apenas de indentação.
Parâmetros de JSON.parse():
JSON.parse() — Consumindo a Saída JSON
Depois de ter uma string JSON de csvToJson(), o próximo passo geralmente é analisá-la de volta em um array JavaScript vivo para filtrar, mapear ou alimentar uma API. A diferença entre uma string JSON (typeof === "string") e um objeto JavaScript importa. Você não pode chamar .filter() ou acessar [0].nome em uma string — você precisa de JSON.parse() primeiro. Esse ciclo completo (stringify depois parse) também funciona como técnica de validação: se sua conversão CSV produzir algo que não seja JSON válido, o parse lançará uma exceção. O argumento opcional reviver permite transformar cada par chave-valor durante a análise — útil para restaurar objetos Date de strings ISO ou renomear chaves sem uma passagem separada.
const csv = `endpoint,metodo,latencia_media_ms,taxa_erro
/api/v2/pedidos,POST,342,0.02
/api/v2/saude,GET,12,0.00
/api/v2/pagamentos,POST,890,0.15
/api/v2/usuarios,GET,45,0.01`
// Passo 1: converter CSV para string JSON
const jsonString = csvToJson(csv, { coerce: true })
// Passo 2: analisar de volta para array JavaScript
const endpoints = JSON.parse(jsonString)
// Verificar se é um array
console.log(Array.isArray(endpoints)) // true
// Filtrar endpoints com alta latência
const lentos = endpoints.filter(ep => ep.latencia_media_ms > 200)
console.log(lentos.map(ep => ep.endpoint))
// ["/api/v2/pedidos", "/api/v2/pagamentos"]
// Desestruturar a primeira linha
const [primeiro, ...resto] = endpoints
console.log(primeiro.endpoint) // "/api/v2/pedidos"
console.log(resto.length) // 3Um wrapper seguro para JSON.parse() é útil ao validar a saída de conversão antes do processamento posterior. Se a conversão de CSV produzir JSON malformado por qualquer motivo (entrada truncada, erros de codificação), isso captura o problema sem travar:
function safeParse(jsonString) {
try {
return { data: JSON.parse(jsonString), error: null }
} catch (err) {
return { data: null, error: err.message }
}
}
// Saída válida
const result = safeParse(csvToJson(csv))
if (result.error) {
console.error('Conversão CSV produziu JSON inválido:', result.error)
} else {
console.log(`Analisadas ${result.data.length} linhas`)
}
// Passando acidentalmente CSV bruto para JSON.parse — isso falha
const bad = safeParse('nome,email\nJoão,jsilva@nexuslabs.io')
console.log(bad.error) // "Unexpected token 'o', "nome,email"... is not valid JSON"Reviver para Renomeação de Chaves e Validação
A função reviver recebe cada par chave-valor durante a análise, das propriedades mais internas para fora. Retornar undefined para uma chave a remove completamente do resultado; retornar um valor diferente o substitui. O reviver é útil para renomear cabeçalhos (camelCase para snake_case), remover campos internos ou verificar se colunas obrigatórias existem. Ele é chamado com o valor raiz por último (chave string vazia), que é onde você lança uma exceção se o resultado não for um array.
const jsonString = csvToJson(`employeeId,firstName,hiredDate
EMP-2847,João,2024-03-15
EMP-3012,Camila,2023-11-01`, { coerce: false })
const camelToSnake = str => str.replace(/[A-Z]/g, c => '_' + c.toLowerCase())
const employees = JSON.parse(jsonString, function(key, value) {
// Valor raiz — validar formato
if (key === '') {
if (!Array.isArray(value)) throw new Error('Esperado array JSON do CSV')
return value
}
// Renomear chaves camelCase para 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: 'João', hired_date: '2024-03-15' }Converter CSV de um Arquivo e de uma Resposta de API
Os dois lugares de onde dados CSV realmente vêm em produção: arquivos em disco e respostas HTTP. Ambos os cenários precisam de tratamento de erros porque a entrada é externa e não controlada.
Ler Arquivo CSV, Converter, Gravar JSON
import { readFileSync, writeFileSync } from 'node:fs'
function csvToJsonFromFile(inputPath, outputPath) {
let csvText
try {
csvText = readFileSync(inputPath, 'utf8')
} catch (err) {
throw new Error(`Falha ao ler ${inputPath}: ${err.message}`)
}
const lines = csvText.trim().split('\n')
if (lines.length < 2) {
throw new Error(`${inputPath} não tem linhas de dados (apenas ${lines.length} linha)`)
}
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(`Convertidas ${rows.length} linhas → ${outputPath}`)
return rows
}
// Uso
const data = csvToJsonFromFile('estoque.csv', 'estoque.json')
console.log(data[0])
// { sku: "WDG-2847", deposito: "us-east-1", quantidade: "150", ... }Buscar CSV de um Endpoint de 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 inesperado: ${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
}
// Exemplo: buscar CSV de taxas de câmbio de um provedor de dados
try {
const rates = await fetchCsvAsJson('https://data.ecb.internal/rates/daily.csv')
console.log(JSON.stringify(rates.slice(0, 3), null, 2))
// Enviar como JSON para serviço downstream
await fetch('https://api.interno/v2/taxas', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ data: rates }),
})
} catch (err) {
console.error('Sincronização de taxas falhou:', err.message)
}JSON.stringify() permite definir uma lista de colunas específicas do CSV. Passe um array de nomes de cabeçalhos para incluir apenas esses campos: JSON.stringify(rows, ['nome', 'email', 'departamento']). Propriedades que não estão no array são silenciosamente excluídas da saída.Conversão de CSV para JSON pela Linha de Comando
O Node.js pode executar scripts inline, e existem ferramentas CLI dedicadas que tratam a conversão de CSV para JSON sem escrever um script.
# Passar CSV por pipe para um script inline do Node.js
cat servidores.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 é um canivete suíço para dados estruturados # Instalar: brew install miller (macOS) ou apt install miller (Debian/Ubuntu) mlr --icsv --ojson cat estoque.csv # Filtrar linhas durante a conversão mlr --icsv --ojson filter '$quantidade > 100' estoque.csv # Selecionar colunas específicas mlr --icsv --ojson cut -f sku,deposito,quantidade estoque.csv
# Instalar globalmente npm install -g csvtojson # Converter arquivo csvtojson servidores.csv > servidores.json # Passar por pipe do stdin cat exportacoes/metricas-t1.csv | csvtojson > metricas-t1.json
Para arquivos grandes, Miller geralmente é a melhor escolha em relação ao csvtojson. Miller é implementado em C e processa CSV como um stream sem carregar o arquivo inteiro na memória, o que significa que ele trata exportações de vários gigabytes com uso de memória constante. Ele também suporta operações em nível de campo inline — renomear colunas, converter tipos, filtrar linhas — antes que os dados se tornem JSON, evitando um pipeline de duas etapas de análise e transformação. O csvtojson, por outro lado, roda em Node.js e é mais conveniente quando o restante do seu conjunto de ferramentas é JavaScript: você pode canalizar sua saída diretamente para streams do Node, importá-lo como biblioteca ou usar sua API colParser para coerção de tipos por coluna no código. Prefira Miller para alta taxa de transferência e pipelines de shell; prefira csvtojson quando precisar de integração próxima com uma aplicação Node.js.
jq não analisa CSV nativamente. Se você precisar do jq no pipeline, converta para JSON primeiro com csvtojson ou mlr, depois passe a saída JSON para o jq para filtrar e transformar.Alternativa de Alto Desempenho — PapaParse
A abordagem manual com split(',') falha em arquivos CSV do mundo real. Campos entre aspas contendo vírgulas, quebras de linha internas, aspas duplas escapadas — tudo isso quebra um divisor ingênuo. PapaParse é a biblioteca que uso quando o CSV vem de uma fonte desconhecida. Ela trata todos os casos extremos da RFC 4180, detecta automaticamente delimitadores e funciona tanto no Node.js quanto em navegadores.
npm install papaparse
import Papa from 'papaparse'
const csv = `produto,descricao,preco,em_estoque
"Widget, Grande","Um widget premium com recursos ""extras""",29.99,true
Kit Parafusos,Kit padrão de parafusos M8,4.50,true
"Conjunto de Gaxetas","Inclui gaxeta, vedação e anel-O",12.75,false`
const { data, errors, meta } = Papa.parse(csv, {
header: true,
dynamicTyping: true, // converte automaticamente números e booleanos
skipEmptyLines: true,
transformHeader: h => h.trim().toLowerCase().replace(/\s+/g, '_'),
})
if (errors.length > 0) {
console.error('Erros de análise:', errors)
}
console.log(JSON.stringify(data, null, 2))
// [
// {
// "produto": "Widget, Grande",
// "descricao": "Um widget premium com recursos \"extras\"",
// "preco": 29.99,
// "em_estoque": true
// },
// ...
// ]
console.log(`Analisadas ${data.length} linhas, delimitador: "${meta.delimiter}"`)A opção dynamicTyping do PapaParse faz a coerção de tipos automaticamente — números se tornam números, "true"/"false" se tornam booleanos. O callback transformHeader normaliza os nomes das colunas para snake_case, evitando que você precise lidar com cabeçalhos inconsistentes de diferentes exportações CSV. Para conversões rápidas sem escrever nenhum código de análise, o conversor de CSV para JSON trata tudo isso no navegador.
Saída no Terminal com Destaque de Sintaxe
Despejar um grande array JSON no terminal cansa os olhos rapidamente. Adicionar destaque de sintaxe à saída facilita a leitura durante debugging e desenvolvimento. O pacote cli-highlight coloriza a saída JSON em terminais Node.js.
npm install cli-highlight
import { highlight } from 'cli-highlight'
// Após converter CSV para array JSON
const jsonOutput = JSON.stringify(rows, null, 2)
// Imprimir com destaque de sintaxe
console.log(highlight(jsonOutput, { language: 'json' }))
// Chaves, strings, números e booleanos recebem cores distintasA saída colorizada vale a pena quando você está inspecionando um resultado grande de conversão interativamente. Chaves JSON, valores string, números e booleanos recebem cores ANSI distintas, facilitando a identificação de um campo com tipo errado — por exemplo, um número de porta que deveria ser 8080 mas aparece destacado como string porque a coerção estava desativada. Isso é especialmente útil ao depurar arquivos CSV exportados de planilhas onde os tipos das colunas são inconsistentes entre linhas. Sem cor, varrer 50 linhas de JSON procurando um único campo com tipo errado significa ler cada valor individualmente. Com cor, um número colorido como string salta aos olhos imediatamente.
Trabalhando com Arquivos CSV Grandes
Carregar um arquivo CSV de 500 MB em uma string com readFileSync() vai consumir memória e potencialmente travar seu processo. Para arquivos grandes, processe o CSV linha por linha em stream e emita objetos JSON conforme eles chegam. O pacote csv-parse (parte do ecossistema csv no npm) fornece um analisador em streaming que funciona com streams do Node.js.
Streaming de CSV para NDJSON com csv-parse
NDJSON (JSON Delimitado por Nova Linha) é um formato onde cada linha do arquivo de saída é um objeto JSON autônomo. Ao contrário de um único array JSON grande — que exige que o arquivo inteiro esteja na memória antes que você possa começar a lê-lo — arquivos NDJSON podem ser processados linha por linha. Isso torna o NDJSON ideal para grandes conjuntos de dados que serão consumidos por processadores de log, pipelines de stream ou bancos de dados com APIs de importação em massa. O pacote csv-parse emite um objeto JavaScript por linha CSV no modo objeto, então você pode canalizá-lo diretamente para um transform stream que acrescenta \n após cada 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'
// Transformar cada objeto de linha CSV em uma linha JSON
const toNdjson = new Transform({
objectMode: true,
transform(record, encoding, callback) {
callback(null, JSON.stringify(record) + '\n')
},
})
await pipeline(
createReadStream('telemetria-2026-03.csv'),
parse({
columns: true, // usar primeira linha como cabeçalhos
skip_empty_lines: true,
trim: true,
cast: true, // converter automaticamente números e booleanos
}),
toNdjson,
createWriteStream('telemetria-2026-03.ndjson')
)
console.log('Conversão em streaming concluída')
// Cada linha no arquivo de saída é um objeto JSON:
// {"timestamp":"2026-03-15T08:22:00Z","servico":"gateway","latencia_ms":42,"status":200}
// {"timestamp":"2026-03-15T08:22:01Z","servico":"auth","latencia_ms":156,"status":401}
// ...Streaming com PapaParse para Navegador e Node.js
O modo streaming do PapaParse usa um callback step que é acionado uma vez por linha em vez de coletar todas as linhas na memória. Você passa um ReadStream do Node.js (no Node.js) ou um objeto File (no navegador) e o PapaParse trata o particionamento internamente. Nenhum pipeline de stream para montar — apenas um callback. Use-o quando precisar de conformidade com a RFC 4180 sem incluir csv-parse.
import Papa from 'papaparse'
import { createReadStream } from 'node:fs'
let rowCount = 0
const errors = []
const fileStream = createReadStream('estoque-deposito.csv')
Papa.parse(fileStream, {
header: true,
dynamicTyping: true,
step(result) {
// Processar uma linha por vez — memória constante
rowCount++
if (result.data.quantidade === 0) {
errors.push(`Linha ${rowCount}: ${result.data.sku} está sem estoque`)
}
},
complete() {
console.log(`Processadas ${rowCount} linhas`)
if (errors.length > 0) {
console.log(`Problemas encontrados: ${errors.length}`)
errors.forEach(e => console.log(` ${e}`))
}
},
error(err) {
console.error('Análise falhou:', err.message)
},
})Erros Comuns
Problema: CSV não é JSON. Passar uma string CSV bruta para JSON.parse() lança um SyntaxError porque vírgulas e quebras de linha não são sintaxe JSON válida.
Solução: Analise o CSV em objetos JavaScript primeiro usando split() ou uma biblioteca, depois use JSON.stringify() para produzir JSON. Chame JSON.parse() apenas em strings que já são JSON válido.
const csv = 'nome,email\nJoão Silva,jsilva@nexuslabs.io' const data = JSON.parse(csv) // SyntaxError: Unexpected token 'o'
const csv = 'nome,email\nJoão Silva,jsilva@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 válidaProblema: Chamar toString() em um objeto JavaScript retorna a string inútil '[object Object]' em vez dos dados reais. Isso destrói silenciosamente sua saída de CSV para JSON.
Solução: Use sempre JSON.stringify() para converter objetos JavaScript em strings JSON. toString() existe para coerção primitiva para string, não para serialização.
const row = { servidor: 'api-gateway', porta: 8080 }
const output = row.toString()
// "[object Object]" — dados perdidosconst row = { servidor: 'api-gateway', porta: 8080 }
const output = JSON.stringify(row, null, 2)
// '{"servidor":"api-gateway","porta":8080}'Problema: Um split(",") ingênuo quebra quando valores CSV contêm vírgulas dentro de campos entre aspas: "Widget, Grande" se torna dois valores separados em vez de um.
Solução: Use PapaParse ou csv-parse para qualquer dado CSV que você não controla completamente. Se precisar analisar manualmente, implemente um analisador por máquina de estados que rastreie se a posição atual está dentro de um campo entre aspas.
const line = '"Widget, Grande","Qualidade premium",29.99'
const values = line.split(',')
// ["\"Widget", " Grande\"", "\"Qualidade premium\"", "29.99"]
// 4 valores em vez de 3 — primeiro campo dividido incorretamenteimport Papa from 'papaparse'
const { data } = Papa.parse('"Widget, Grande","Qualidade premium",29.99')
// data[0] = ["Widget, Grande", "Qualidade premium", "29.99"]
// 3 valores, analisados corretamenteProblema: Sem coerção de tipos, porta: "8080" permanece como string no JSON em vez de número. Sistemas downstream que esperam tipos numéricos rejeitam ou tratam incorretamente os dados.
Solução: Aplique coerção explícita de tipos durante a etapa de mapeamento, ou use PapaParse com dynamicTyping: true. Seja sempre deliberado sobre quais campos devem ser numéricos.
const row = { porta: '8443', debug: 'true', workers: '4' }
JSON.stringify(row)
// {"porta":"8443","debug":"true","workers":"4"} — tudo stringsconst row = {
porta: Number('8443'), // 8443
debug: 'true' === 'true', // true
workers: Number('4'), // 4
}
JSON.stringify(row)
// {"porta":8443,"debug":true,"workers":4} — tipos corretosAnálise Manual vs Bibliotecas — Comparação Rápida
Para scripts rápidos em que você controla o formato CSV e sabe que não há campos entre aspas, a abordagem nativa com split() + JSON.stringify() funciona e requer zero dependências. Para sistemas em produção que processam arquivos CSV enviados por usuários, use PapaParse no navegador ou csv-parse no Node.js — ambos tratam a RFC 4180 corretamente e suportam streaming. O pacote csvtojson é o único que produz JSON diretamente, tratando tanto a análise quanto a serialização em uma única chamada. Quando você precisar do caminho mais rápido do colar ao resultado, o conversor de CSV para JSON resolve tudo no navegador sem nenhuma configuração.
Perguntas Frequentes
Como converter CSV para JSON em JavaScript sem usar uma biblioteca?
Divida a string CSV por quebras de linha para obter as linhas, extraia os cabeçalhos da primeira linha com split(","), depois mapeie as demais linhas para objetos cujas chaves são esses cabeçalhos. Finalize com JSON.stringify(array, null, 2) para produzir uma string JSON formatada. Essa abordagem funciona bem para arquivos CSV simples em que você controla o formato e sabe que não há campos com aspas ou vírgulas internas. Para dados vindos de exportações de planilhas ou sistemas de terceiros, campos entre aspas e valores multilinha quebram um divisor ingênuo — nesse caso, use PapaParse ou csv-parse. Para arquivos muito pequenos processados no navegador, essa abordagem sem dependências é ideal.
const csv = `nome,email,departamento
João Silva,jsilva@nexuslabs.io,Engenharia
Camila Rocha,crocha@nexuslabs.io,Produto`
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))
// [
// { "nome": "João Silva", "email": "jsilva@nexuslabs.io", "departamento": "Engenharia" },
// { "nome": "Camila Rocha", "email": "crocha@nexuslabs.io", "departamento": "Produto" }
// ]Qual é a diferença entre JSON.stringify() e toString() para objetos?
toString() em um objeto simples retorna a string inútil "[object Object]" — ela não diz nada sobre os dados reais. JSON.stringify() produz uma string JSON válida com todas as chaves e valores devidamente serializados, incluindo objetos e arrays aninhados. Use sempre JSON.stringify() quando precisar converter um objeto JavaScript (como uma linha derivada de CSV) em uma string JSON. Para reverter a operação — reconstruir objetos JavaScript vivos a partir de uma string JSON — use JSON.parse(), que é o inverso exato de JSON.stringify(). Essas duas funções formam um ciclo completo: stringify para persistir ou transmitir dados, parse para consumi-los.
const row = { nome: 'João Silva', cargo: 'Engenheiro' }
console.log(row.toString()) // "[object Object]"
console.log(JSON.stringify(row)) // '{"nome":"João Silva","cargo":"Engenheiro"}'Como lidar com campos CSV que contêm vírgulas ou aspas?
A RFC 4180 especifica que campos que contêm vírgulas, quebras de linha ou aspas duplas devem ser envolvidos em aspas duplas, com as aspas internas escapadas dobrando-as ("" dentro de um campo entre aspas representa uma aspa literal). Um split(",") manual quebra nesses arquivos — o limite do campo não é mais uma vírgula simples. Use PapaParse ou csv-parse para dados em produção, ou escreva um analisador por máquina de estados que rastreie se você está dentro de um campo entre aspas. Escrever uma máquina de estados correta do zero é surpreendentemente trabalhoso: você precisa lidar com aspas no início de um campo, aspas escapadas no meio do campo, quebras de linha dentro de campos entre aspas e diferentes convenções de fim de linha (CRLF vs LF). Para qualquer dado CSV além do trivial, use uma biblioteca bem testada.
// PapaParse trata RFC 4180 corretamente
import Papa from 'papaparse'
const csv = `produto,descricao,preco
"Widget, Grande","Um ""widget"" premium",29.99
Parafuso,Parafuso padrão,1.50`
const { data } = Papa.parse(csv, { header: true })
console.log(JSON.stringify(data, null, 2))
// campo descricao contém corretamente: Um "widget" premiumPosso converter CSV para JSON diretamente no navegador?
Sim. Tanto JSON.stringify() quanto JSON.parse() são nativos em todos os motores de navegador. Para a etapa de análise do CSV, você pode dividir por quebra de linha e vírgula para arquivos simples, ou incluir PapaParse via CDN (ele não tem dependências do Node.js). Toda a conversão acontece no lado do cliente sem nenhum round-trip ao servidor, o que é útil para privacidade dos dados — o CSV bruto nunca sai da máquina do usuário. Quando um usuário faz upload de um arquivo CSV via elemento <input type="file">, o método file.text() da File API retorna uma Promise que resolve para o conteúdo do arquivo como string, que você pode passar para sua função de conversão. Isso torna a conversão CSV para JSON totalmente no navegador prática para dashboards, ferramentas de desenvolvimento e qualquer aplicação que precise processar dados enviados sem um backend.
// Navegador: usuário faz upload de um arquivo 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))
})Como analisar valores numéricos e booleanos do CSV em vez de manter tudo como strings?
CSV não tem sistema de tipos — todo campo é uma string. Você precisa converter os valores durante a etapa de mapeamento. Verifique padrões numéricos com Number() ou parseFloat(), converta "true"/"false" para booleanos e trate strings vazias como null. Tome cuidado com campos que parecem números mas devem permanecer como strings: CEPs como "01310-100" perdem seu formato ao serem convertidos com Number(), e números de telefone ou códigos de produto com caracteres numéricos são igualmente frágeis. A biblioteca csvtojson faz coerção automática de tipos via a opção colParser, que permite especificar funções de conversão por coluna e substituir a detecção automática em colunas problemáticas. A opção dynamicTyping do PapaParse aplica a mesma coerção globalmente em todas as colunas.
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
}
// Aplicar durante o mapeamento de CSV para objeto
const row = { porta: coerceValue('8443'), debug: coerceValue('true'), host: coerceValue('api.interno') }
// { porta: 8443, debug: true, host: "api.interno" }Como gravar a saída de CSV para JSON em um arquivo no Node.js?
Use fs.writeFileSync() com a saída de JSON.stringify(). O terceiro argumento de JSON.stringify controla a indentação — passe 2 para dois espaços ou "\t" para tabulações. Para ler o arquivo de volta, use JSON.parse(fs.readFileSync(path, "utf8")), que reconstrói o array JavaScript vivo de objetos. Se você estiver gravando o arquivo em um contexto assíncrono (dentro de uma função async ou no nível superior de um módulo ES), prefira fs.promises.writeFile() para evitar bloquear o event loop durante a gravação. Para saídas JSON grandes acima de alguns megabytes, considere canalizar um stream JSON para um WriteStream em vez de construir a string inteira na memória antes de gravar.
import { writeFileSync, readFileSync } from 'node:fs'
// Gravar
const jsonOutput = JSON.stringify(rows, null, 2)
writeFileSync('funcionarios.json', jsonOutput, 'utf8')
// Ler de volta
const parsed = JSON.parse(readFileSync('funcionarios.json', 'utf8'))
console.log(Array.isArray(parsed)) // true
console.log(parsed[0].nome) // "João Silva"Ferramentas Relacionadas
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.