Artigo Build·Desenvolvimento·13 min de leitura de leitura

Como Exportar Dados JSON para Excel (2026): Guia Completo com SheetJS

Exportar JSON para Excel (.xlsx) é tarefa comum em dashboards e relatórios — e enganosamente simples quando se escolhe a biblioteca certa. Este guia cobre SheetJS e ExcelJS em JavaScript, OpenPyXL em Python, múltiplas planilhas, formatação, fórmulas e estratégias para arquivos grandes.

Vitor Morais

Por Vitor Morais

Fundador do MochaLabz ·

📊

Converta JSON ↔ CSV

Alternativa rápida pra dados simples — abre direto em Excel e Google Sheets.

Usar conversor →

Exportar JSON para Excel (.xlsx) é requisito recorrente em qualquer dashboard ou ERP sério. Analista quer receber relatório que abre no Excel. Gestor pede dashboard exportável. Compliance exige evidência em formato preservável. E CSV, embora simples, perde formatação, tipos e capacidade de múltiplas planilhas — limitações que afastam usuários não-técnicos.

Este guia cobre as ferramentas padrão (SheetJS em JavaScript, OpenPyXL em Python), múltiplas planilhas em um único arquivo, preservação de tipos, formatação rica com ExcelJS, geração de fórmulas e estratégias para arquivos grandes que não travam o browser.

Quando Excel vence CSV

Excel (.xlsx) vs CSV
CritérioExcel (.xlsx)CSV
Tamanho do arquivoMaior (comprimido)Menor
Múltiplas planilhasSimNão
Preservação de tiposSim (datas, números, booleanos)Não (tudo é string)
Formatação visualCores, bordas, fonte, gráficosNão
FórmulasSimNão
Performance (1M linhas)Lento mas funcionaRápido
Integração com outros sistemasMédiaAlta (universal)
Abertura em Excel/SheetsPerfeitaPode quebrar por encoding/delimitador

SheetJS: a biblioteca padrão em JavaScript

npm install xlsx

Exportação básica

import * as XLSX from "xlsx"; const data = [ { id: 1, nome: "João", email: "joao@exemplo.com", valor: 1500.5 }, { id: 2, nome: "Maria", email: "maria@exemplo.com", valor: 2300.0 }, { id: 3, nome: "Pedro", email: "pedro@exemplo.com", valor: 890.75 }, ]; // 1. Converte JSON em worksheet const worksheet = XLSX.utils.json_to_sheet(data); // 2. Cria workbook e adiciona a sheet const workbook = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(workbook, worksheet, "Clientes"); // 3. Gera arquivo e baixa (no browser) XLSX.writeFile(workbook, "dados.xlsx");

Configurando cabeçalhos personalizados

// Com header customizado const worksheet = XLSX.utils.json_to_sheet(data, { header: ["id", "nome", "email", "valor"], // ordem explícita }); // Ou com nomes em português const dataFormatada = data.map((row) => ({ ID: row.id, "Nome Completo": row.nome, "E-mail": row.email, "Valor (R$)": row.valor, })); const worksheetBr = XLSX.utils.json_to_sheet(dataFormatada);

Múltiplas planilhas no mesmo arquivo

const clientes = [...]; // array de clientes const pedidos = [...]; // array de pedidos const produtos = [...]; // array de produtos const workbook = XLSX.utils.book_new(); // Planilha 1: Clientes const sheetClientes = XLSX.utils.json_to_sheet(clientes); XLSX.utils.book_append_sheet(workbook, sheetClientes, "Clientes"); // Planilha 2: Pedidos const sheetPedidos = XLSX.utils.json_to_sheet(pedidos); XLSX.utils.book_append_sheet(workbook, sheetPedidos, "Pedidos"); // Planilha 3: Produtos const sheetProdutos = XLSX.utils.json_to_sheet(produtos); XLSX.utils.book_append_sheet(workbook, sheetProdutos, "Produtos"); XLSX.writeFile(workbook, "relatorio-completo.xlsx"); // Usuário recebe 1 arquivo com 3 abas

Dica

Nome das abas tem limite de 31 caracteres no Excel. SheetJS trunca automaticamente, mas é melhor você controlar: nome curto e descritivo (“Jan-2026”, “Clientes PF”). Abas com caracteres especiais (/ \\ : ? *) podem quebrar alguns leitores antigos.

Preservando tipos: datas, números e booleanos

const data = [ { id: 1, nome: "João", criadoEm: new Date("2026-04-20"), // tipo Date → preserva valor: 1500.50, // tipo number → preserva decimal ativo: true, // tipo boolean → preserva }, ]; const worksheet = XLSX.utils.json_to_sheet(data, { cellDates: true, // importante para datas }); const workbook = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(workbook, worksheet, "Dados"); XLSX.writeFile(workbook, "com-tipos.xlsx");

Atenção

Se o JSON tem data como string ISO (“2026-04-20”), SheetJS trata como texto. Converta para Date antes de exportar: new Date(row.criadoEm). Para datas em Excel formato brasileiro (DD/MM/YYYY), aplique formatação customizada: worksheet["A2"].z = "dd/mm/yyyy".

Fórmulas no Excel

const data = [ { produto: "A", preco: 100, quantidade: 5 }, { produto: "B", preco: 50, quantidade: 10 }, { produto: "C", preco: 75, quantidade: 3 }, ]; const worksheet = XLSX.utils.json_to_sheet(data); // Adiciona coluna de Total (fórmula = preço * quantidade) XLSX.utils.sheet_add_aoa(worksheet, [["Total"]], { origin: "D1" }); // Fórmula em D2, D3, D4 for (let i = 2; i <= data.length + 1; i++) { worksheet[`D${i}`] = { f: `B${i}*C${i}` }; } // Soma total em D5 worksheet["D5"] = { f: `SUM(D2:D${data.length + 1})` }; const workbook = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(workbook, worksheet, "Produtos"); XLSX.writeFile(workbook, "com-formulas.xlsx");

ExcelJS: formatação rica (cores, bordas, fontes)

Para relatórios corporativos com branding visual, SheetJS não basta. Use ExcelJS:

npm install exceljs
import ExcelJS from "exceljs"; async function gerarRelatorio(data: any[]) { const workbook = new ExcelJS.Workbook(); const sheet = workbook.addWorksheet("Relatório"); // Colunas com tipos e formatação sheet.columns = [ { header: "ID", key: "id", width: 10 }, { header: "Nome", key: "nome", width: 30 }, { header: "E-mail", key: "email", width: 35 }, { header: "Valor", key: "valor", width: 15, style: { numFmt: '"R$"#,##0.00' }, }, { header: "Data", key: "data", width: 15, style: { numFmt: "dd/mm/yyyy" } }, ]; // Adiciona linhas sheet.addRows(data); // Formata cabeçalho const headerRow = sheet.getRow(1); headerRow.font = { bold: true, color: { argb: "FFFFFFFF" } }; headerRow.fill = { type: "pattern", pattern: "solid", fgColor: { argb: "FF28190A" }, // mocha }; headerRow.alignment = { vertical: "middle", horizontal: "center" }; // Bordas em todas as células sheet.eachRow((row) => { row.eachCell((cell) => { cell.border = { top: { style: "thin" }, left: { style: "thin" }, bottom: { style: "thin" }, right: { style: "thin" }, }; }); }); // Congela cabeçalho ao scroll sheet.views = [{ state: "frozen", ySplit: 1 }]; // Salvar if (typeof window !== "undefined") { // Browser: download const buffer = await workbook.xlsx.writeBuffer(); const blob = new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", }); const url = URL.createObjectURL(blob); const link = document.createElement("a"); link.href = url; link.download = "relatorio.xlsx"; link.click(); URL.revokeObjectURL(url); } else { // Node.js: filesystem await workbook.xlsx.writeFile("./relatorio.xlsx"); } }

Python: OpenPyXL

pip install openpyxl
from openpyxl import Workbook from openpyxl.styles import Font, PatternFill, Alignment, Border, Side data = [ {"id": 1, "nome": "João", "email": "joao@exemplo.com", "valor": 1500.50}, {"id": 2, "nome": "Maria", "email": "maria@exemplo.com", "valor": 2300.00}, ] wb = Workbook() ws = wb.active ws.title = "Clientes" # Cabeçalho headers = list(data[0].keys()) ws.append(headers) # Linhas for row in data: ws.append(list(row.values())) # Formatação do cabeçalho header_font = Font(bold=True, color="FFFFFF") header_fill = PatternFill("solid", fgColor="28190A") header_alignment = Alignment(horizontal="center", vertical="center") for cell in ws[1]: cell.font = header_font cell.fill = header_fill cell.alignment = header_alignment # Ajustar largura das colunas ws.column_dimensions["A"].width = 10 ws.column_dimensions["B"].width = 30 ws.column_dimensions["C"].width = 35 ws.column_dimensions["D"].width = 15 # Salvar wb.save("relatorio.xlsx")

Pandas para exports simples

pip install pandas openpyxl
import pandas as pd data = [ {"id": 1, "nome": "João", "valor": 1500.50}, {"id": 2, "nome": "Maria", "valor": 2300.00}, ] df = pd.DataFrame(data) # Exportação simples (uma planilha) df.to_excel("dados.xlsx", index=False) # Múltiplas planilhas with pd.ExcelWriter("relatorio.xlsx", engine="openpyxl") as writer: df_clientes.to_excel(writer, sheet_name="Clientes", index=False) df_pedidos.to_excel(writer, sheet_name="Pedidos", index=False) df_produtos.to_excel(writer, sheet_name="Produtos", index=False)

Casos de uso reais

Dashboard com export de relatório

"use client"; import * as XLSX from "xlsx"; interface Pedido { id: number; cliente: string; valor: number; data: Date; } export function BotaoExportarPedidos({ pedidos }: { pedidos: Pedido[] }) { const exportar = () => { const ws = XLSX.utils.json_to_sheet(pedidos, { cellDates: true }); const wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, "Pedidos"); const hoje = new Date().toISOString().slice(0, 10); XLSX.writeFile(wb, `pedidos-${hoje}.xlsx`); }; return ( <button onClick={exportar} disabled={pedidos.length === 0}> Exportar {pedidos.length} pedidos </button> ); }

Relatório mensal com resumo

async function gerarRelatorioMensal(mes: string) { const pedidos = await db.pedido.findMany({ where: { mesReferencia: mes }, }); const workbook = XLSX.utils.book_new(); // Aba 1: Pedidos detalhados const sheetPedidos = XLSX.utils.json_to_sheet(pedidos, { cellDates: true }); XLSX.utils.book_append_sheet(workbook, sheetPedidos, "Detalhado"); // Aba 2: Resumo por cliente const resumoCliente = agruparPorCliente(pedidos); const sheetResumo = XLSX.utils.json_to_sheet(resumoCliente); XLSX.utils.book_append_sheet(workbook, sheetResumo, "Por Cliente"); // Aba 3: Totais const totais = [{ total_pedidos: pedidos.length, receita_total: pedidos.reduce((s, p) => s + p.valor, 0), ticket_medio: pedidos.reduce((s, p) => s + p.valor, 0) / pedidos.length, }]; const sheetTotais = XLSX.utils.json_to_sheet(totais); XLSX.utils.book_append_sheet(workbook, sheetTotais, "Totais"); XLSX.writeFile(workbook, `relatorio-${mes}.xlsx`); }

Performance em arquivos grandes

SheetJS - tempo aproximado por tamanho
CritérioTempo em JS moderno
1.000 linhas × 10 colunas~50 ms
10.000 linhas~300 ms
100.000 linhas~3-5 s (UI bloqueada no browser)
1.000.000 linhas~30-60 s (usar Node.js)

Vai mais fundo

Para arquivos acima de 50k linhas gerados no browser, use Web Worker — mantém UI responsiva. Para milhões de linhas, gere no servidor (Node.js) e entregue via URL de download. Para ingestão contínua (streaming), exceljs tem writeWorkbook stream. Na dúvida, comece com SheetJS + download direto; otimize quando travar.

Estratégia: quando Excel, quando CSV, quando JSON

Qual formato usar em cada cenário
CritérioFormato recomendadoMotivo
Relatório para analista B2B.xlsx com múltiplas abasPreserva tipos, abre perfeito no Excel
Export para integração com sistema.jsonTipos preservados, universal em código
Dump grande para análise.csvLeve, manipulável em Pandas/SQL
Download para usuário final não-técnico.xlsxAbre direto no Excel, sem configuração
Dados para Google Sheets.csv ou .xlsxGoogle Sheets aceita ambos
Log de eventos.jsonAppend-friendly, estruturado
Backup de banco.sql ou dump proprietárioPreserva estrutura e constraints

Formatação específica: valores monetários e percentuais

// Em ExcelJS sheet.getColumn("valor").numFmt = '"R$"#,##0.00'; sheet.getColumn("percentual").numFmt = "0.00%"; sheet.getColumn("data").numFmt = "dd/mm/yyyy"; sheet.getColumn("datahora").numFmt = "dd/mm/yyyy hh:mm"; // Em OpenPyXL from openpyxl.styles import NamedStyle moeda = NamedStyle(name="moeda", number_format='"R$"#,##0.00') ws["D2"].style = moeda

Headers em negrito + congelar linha

// ExcelJS const headerRow = sheet.getRow(1); headerRow.font = { bold: true, size: 12 }; headerRow.fill = { type: "pattern", pattern: "solid", fgColor: { argb: "FFE0E0E0" }, }; // Congela linha 1 (ficará sempre visível no scroll) sheet.views = [{ state: "frozen", ySplit: 1 }];

Validação de dados na célula (dropdown, regra)

// ExcelJS - dropdown com valores válidos sheet.getCell("E2").dataValidation = { type: "list", allowBlank: false, formulae: ['"ativo,inativo,pendente"'], showErrorMessage: true, errorStyle: "error", errorTitle: "Status inválido", error: "Selecione: ativo, inativo ou pendente", };

Proteção de planilha (read-only)

// ExcelJS - protege toda a planilha (só leitura) await sheet.protect("senha123", { selectLockedCells: true, selectUnlockedCells: true, }); // Permite edição de célula específica sheet.getCell("E2").protection = { locked: false };

Erros clássicos

  • Datas viradas número (44000...): não configurou cellDates. Converta para Date antes ou use cellDates: true.
  • Valor decimal virar inteiro: JSON enviou como string. Converta explicitamente para number.
  • Acento quebrado na abertura: arquivo gerado sem UTF-8. SheetJS gera UTF-8 por padrão — se quebrou, problema no JSON de origem.
  • Aba sem nome ou duplicada: Excel não aceita duas abas com mesmo nome. Valide.
  • Arquivo grande congelando browser: use Web Worker ou Node.js backend.
  • Fórmula não recalculando: Excel precisa abrir o arquivo para calcular. Ao abrir, valores aparecem.
  • Formatação não aplicada: aplicou antes de addRows. Aplique depois das linhas existirem.

Fluxo completo end-to-end

Cenário típico: API paginada devolve pedidos; frontend oferece botão para exportar relatório do mês:

"use client"; import { useState } from "react"; import * as XLSX from "xlsx"; async function buscarTodosPedidos(mes: string) { const todos = []; let pagina = 1; while (true) { const res = await fetch(`/api/pedidos?mes=${mes}&page=${pagina}`); const { data, hasMore } = await res.json(); todos.push(...data); if (!hasMore) break; pagina++; } return todos; } export function ExportarPedidosBotao({ mes }: { mes: string }) { const [loading, setLoading] = useState(false); const handleClick = async () => { setLoading(true); try { const pedidos = await buscarTodosPedidos(mes); // Converter datas string → Date const pedidosComDate = pedidos.map((p) => ({ ...p, criadoEm: new Date(p.criadoEm), })); const wb = XLSX.utils.book_new(); const sheetDetalhado = XLSX.utils.json_to_sheet(pedidosComDate, { cellDates: true, }); XLSX.utils.book_append_sheet(wb, sheetDetalhado, "Pedidos"); // Resumo const totais = [{ total: pedidos.length, receita: pedidos.reduce((s, p) => s + p.valor, 0), ticketMedio: pedidos.reduce((s, p) => s + p.valor, 0) / pedidos.length, }]; const sheetResumo = XLSX.utils.json_to_sheet(totais); XLSX.utils.book_append_sheet(wb, sheetResumo, "Resumo"); XLSX.writeFile(wb, `pedidos-${mes}.xlsx`); } catch (err) { console.error(err); alert("Erro ao exportar"); } finally { setLoading(false); } }; return ( <button onClick={handleClick} disabled={loading}> {loading ? "Gerando..." : `Exportar ${mes} em Excel`} </button> ); }

Exportar em uma frase

Exportar JSON para Excel em 2026 é tarefa resolvida: SheetJS cobre 90% dos casos em 10 linhas de código, ExcelJS adiciona formatação rica quando necessário, OpenPyXL entrega mesmo para Python. Preservação de tipos, múltiplas abas e fórmulas são suportadas nativamente. A complexidade vem de performance em arquivos grandes (use backend Node.js) e de formatação visual elaborada (use ExcelJS).

Perguntas frequentes

Qual biblioteca usar para exportar JSON para Excel em JavaScript?+

SheetJS (xlsx) é o padrão absoluto em 2026. Suporta leitura e escrita de .xlsx, .xls, .ods, .csv. Gera no browser e Node.js. API limpa via XLSX.utils.json_to_sheet e XLSX.writeFile. Alternativa: exceljs, mais focada em formatação avançada (bordas, cores, gráficos). Para 90% dos casos, SheetJS basta. Para relatórios complexos com branding visual, considere exceljs.

Excel ou CSV — qual escolher?+

Excel (.xlsx) preserva tipos (datas, números, fórmulas), suporta múltiplas planilhas, cores e formatação. CSV é texto simples, universal, mais leve. Use Excel quando: relatório formal, contém dados de tipos variados, será editado pelo usuário final. Use CSV quando: integração com outros sistemas, exportação grande (100k+ linhas), compatibilidade máxima. Para usuário brasileiro final abrindo em Excel, .xlsx vence sempre.

Como exportar múltiplas planilhas em um único arquivo?+

Em SheetJS: cria workbook, adiciona várias sheets via XLSX.utils.book_append_sheet(wb, sheet, 'nome'). Cada sheet é um JSON diferente. Útil para relatórios segmentados (aba Clientes, aba Pedidos, aba Resumo). Em OpenPyXL (Python): workbook.create_sheet('nome') para cada. Usuário recebe um .xlsx único com todas as abas preenchidas. Padrão em exportação de dashboard.

Excel abre arquivo grande (100k+ linhas) sem travar?+

Excel moderno (2019+) abre até 1 milhão de linhas por aba sem travar, embora lento. Para volumes maiores ou visualização fluida, divida em múltiplas abas ou considere formato alternativo (CSV, Parquet). SheetJS gera .xlsx de 1M linhas em ~30-60 segundos em Node.js. No browser, acima de 100k, use Web Worker para não congelar UI durante conversão.

Como preservar tipos de dados (data, número decimal) no Excel?+

SheetJS infere tipos do JSON: string vira texto, number vira número, boolean vira booleano. Datas precisam cuidado: se JSON tem Date, SheetJS converte automaticamente (cellDates: true). Se tem string ISO (2026-04-20), SheetJS trata como texto por padrão — converta para Date antes de exportar ou use XLSX.utils.sheet_to_json com raw: false no read.

Posso gerar Excel com fórmulas?+

Sim, em ambas SheetJS e ExcelJS. Em SheetJS: cell.f = 'SUM(A1:A10)' define fórmula. Ao abrir no Excel, a fórmula é calculada. Útil para relatórios onde usuário pode atualizar valor de entrada e ver totais recalculados. Em exceljs, API mais rica: cell.value = { formula: 'SUM(A1:A10)', result: 1000 }.

Como adicionar formatação (cores, bordas, fonte)?+

SheetJS plain não suporta formatação rica (só estrutura). Para formatação, use SheetJS Pro (pago) ou biblioteca exceljs (grátis, open source, mais pesada). ExcelJS permite cores de células, bordas, fonte, merge, condicional formatting. Para relatórios corporate com branding, exceljs é a escolha. Para export funcional simples, SheetJS é suficiente.

Como gerar download automático do .xlsx no browser?+

SheetJS tem XLSX.writeFile(workbook, 'dados.xlsx') que dispara download automaticamente no browser. No Node.js, escreve no filesystem. Alternativamente, use XLSX.write(wb, { type: 'buffer' }) para obter Buffer e criar Blob + download manual (útil para integração com outras bibliotecas ou APIs).

#excel#xlsx#json#sheetjs#exceljs#openpyxl#javascript#python#export#planilha

Artigos relacionados