Leer y escribir Excel en Node.js con ExcelJS

Aprende a leer y escribir Excel en Node.js con ExcelJS: crear un archivo y leerlo después, sin tener Excel instalado.

Tarde o temprano alguien te pide “¿me lo pasas en Excel?”. Puede ser un reporte de ventas, una lista de usuarios o el inventario del mes. Y también pasa al revés: te mandan un Excel con cien filas y tienes que meterlas a la base de datos sin copiar y pegar a mano.

Para las dos cosas uso ExcelJS. Funciona en el servidor sin necesitar Excel, lee y escribe archivos .xlsx, y deja ponerle estilos, fórmulas y formatos. Aquí vemos cómo leer y escribir Excel en Node.js con un ejemplo pequeño: una lista de productos.

Probé todo el código con Node.js 22 y ExcelJS 4.4.0. Si usas otra versión y algo no te funciona, revisa primero eso.

Instalar ExcelJS

Crea una carpeta, inicia el proyecto e instala el paquete:

mkdir excel-demo
cd excel-demo
npm init -y
npm install exceljs

Escribir un archivo de Excel

Crea un archivo escribir.js:

const ExcelJS = require('exceljs');

async function crearExcel() {
  const libro = new ExcelJS.Workbook();
  const hoja = libro.addWorksheet('Productos');

  hoja.columns = [
    { header: 'Producto', key: 'producto', width: 25 },
    { header: 'Precio', key: 'precio', width: 12 },
    { header: 'Stock', key: 'stock', width: 10 },
  ];

  hoja.addRow({ producto: 'Teclado mecánico', precio: 899.5, stock: 12 });
  hoja.addRow({ producto: 'Mouse inalámbrico', precio: 349, stock: 30 });
  hoja.addRow({ producto: 'Monitor 24"', precio: 2899.99, stock: 5 });

  await libro.xlsx.writeFile('productos.xlsx');
  console.log('Archivo creado: productos.xlsx');
}

crearExcel();

Lo que pasa aquí, en orden:

  • Workbook es el archivo completo y addWorksheet crea una hoja con el nombre que le pongas.
  • hoja.columns define los encabezados. El key es el nombre con el que después agregas los datos, y width el ancho de la columna.
  • addRow agrega una fila. Si le pasas un objeto, ExcelJS acomoda cada valor en la columna que tenga ese key.
  • writeFile guarda el archivo en disco y devuelve una promesa, por eso usamos await.

Darle estilo y formato

Un Excel con el encabezado en negritas y los precios con signo de pesos se ve mucho mejor. Agrega esto antes de writeFile:

// Encabezado en negritas
hoja.getRow(1).font = { bold: true };

// Formato de moneda para toda la columna de precio
hoja.getColumn('precio').numFmt = '$#,##0.00';

Agregar una fórmula

También puedes meter fórmulas. Aquí calculamos el valor total del inventario (precio por stock de cada producto):

hoja.getCell('E1').value = 'Total inventario';
hoja.getCell('E2').value = { formula: 'SUMPRODUCT(B2:B4,C2:C4)' };

Ojo con esto: ExcelJS no calcula la fórmula, solo la guarda. Excel la calcula cuando abres el archivo. Más abajo te explico por qué esto da problemas al leer.

Leer un archivo de Excel

Ahora el camino contrario. Crea leer.js:

const ExcelJS = require('exceljs');

async function leerExcel() {
  const libro = new ExcelJS.Workbook();
  await libro.xlsx.readFile('productos.xlsx');

  const hoja = libro.getWorksheet('Productos');
  const productos = [];

  hoja.eachRow((fila, numeroFila) => {
    if (numeroFila === 1) return; // saltamos el encabezado

    productos.push({
      producto: fila.getCell(1).value,
      precio: fila.getCell(2).value,
      stock: fila.getCell(3).value,
    });
  });

  console.log(productos);
}

leerExcel();

Aquí readFile carga el archivo, getWorksheet busca la hoja por su nombre y eachRow recorre las filas una por una. Como la fila 1 es el encabezado, la saltamos con un return. Las celdas se leen con getCell, y empiezan en 1, no en 0.

Con esto ya tienes un arreglo de objetos listo para guardarlo en tu base de datos, mandarlo por una API o lo que necesites.

Resultado: leer y escribir Excel en Node.js

Primero corre el archivo que escribe y luego el que lee:

node escribir.js
node leer.js

La consola muestra esto:

Archivo creado: productos.xlsx
[
  { producto: 'Teclado mecánico', precio: 899.5, stock: 12 },
  { producto: 'Mouse inalámbrico', precio: 349, stock: 30 },
  { producto: 'Monitor 24"', precio: 2899.99, stock: 5 }
]

Y al abrir productos.xlsx en Excel (o en LibreOffice, o en Google Sheets) vas a ver la hoja “Productos” con el encabezado en negritas, los precios con formato de moneda y, en la celda E2, el total del inventario: 35,763.95.

Show Image

(Aquí va tu captura del Excel abierto)

Los números salen como números y no como texto, así que puedes hacer cuentas con ellos sin convertir nada. Eso es justo lo que quieres cuando importas datos.

Errores comunes

Estos son los que más se repiten con ExcelJS:

1. La fórmula se lee como un objeto y no como un número

Si escribes una fórmula sin resultado y luego lees la celda, no recibes el valor, recibes esto:

console.log(hoja.getCell('E2').value);
// { formula: 'SUMPRODUCT(B2:B4,C2:C4)' }

Eso pasa porque ExcelJS no calcula nada. Si necesitas el valor, guárdalo junto con la fórmula:

hoja.getCell('A3').value = { formula: 'SUM(A1:A2)', result: 30 };

Al leerla de vuelta te llegan los dos: { formula: 'SUM(A1:A2)', result: 30 }. Así otros programas que no recalculan también van a ver el número.

2. getWorksheet devuelve undefined

Casi siempre es que el nombre de la hoja no coincide, y ahí truena todo lo que sigue. Revisa mayúsculas, acentos y espacios al final. Mientras pruebas, también puedes usar libro.worksheets[0] para tomar la primera hoja sin importar cómo se llame.

3. fila.values trae un hueco al inicio

Como las columnas empiezan en 1, el arreglo tiene la posición 0 vacía. Si lo usas, acuérdate de ese hueco.

4. Las fechas se guardan en UTC

Si estás en México (UTC-6) y escribes new Date(2026, 9, 4), que es el 4 de octubre a medianoche de tu hora, ExcelJS lo guarda como las 06:00 UTC. Al abrir el archivo en Excel con formato de hora vas a ver 6:00 a. m. y no 12:00 a. m. Al leerla de vuelta recibes un objeto Date que sí es el mismo momento, pero si lo formateas en UTC te va a dar otra hora. Si solo te importa el día, trabaja siempre con la misma zona horaria al escribir y al leer.

5. Solo funciona con .xlsx

Los .xls viejos no los abre. Si te los mandan así, hay que guardarlos primero como .xlsx desde Excel.

6. Archivos muy grandes

Con readFile todo el archivo se carga en memoria. Para decenas de miles de filas conviene usar el modo de streaming que trae ExcelJS. Lo explico en otro artículo.

(Si tienes alguna anécdota real con Excel en producción, este es el lugar para contarla en uno o dos párrafos. Por ejemplo, un reporte que se rompió por las fechas o un archivo que tardó una eternidad en cargar.)

Recomendaciones

  • Cuando leas y escribas Excel en Node.js, no confíes en que el archivo que te mandan viene bien. Revisa que la hoja exista, que los encabezados sean los que esperas y que las celdas no estén vacías antes de guardar nada en la base de datos.
  • Si vas a generar archivos desde una API, usa libro.xlsx.writeBuffer() en lugar de writeFile. Así devuelves el archivo directo en la respuesta sin guardarlo en el disco del servidor.
  • Deja los encabezados y el formato definidos en un solo lugar. Cuando te pidan cambiar una columna, vas a agradecer no tener que buscarla por todo el código.

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *