115

I am a nodejs programmer . Now I have a table of data that I want to save in Excel File format . How do I go about doing this ?

I found a few Node libraries . But most of them are Excel Parsers rather than Excel Writers .I am using a Linux Server . Hence need something that can run on Linux . Please let me know if there are any helpful libraries that you know of .

Or is there a way I can convert a CSV file to an xls file ( programmatically ) ?

geeky_monster
  • 8,672
  • 18
  • 55
  • 86
  • Easiest way I found is just to read and write a .xlsx file instead of .xls: Create a multi-tab spreadsheet in Excel and save it out as a Strict XML Spreadsheet (.xlsx). Then rename to .zip, unzip, change contents, rezip, change to .xlsx. Easy. Saves faffing with other libraries, especially if you want to use it in client React etc which these days requires polyfills to get node libraries working. – pshmath0 Mar 24 '23 at 07:50

11 Answers11

137

excel4node is a maintained, native Excel file creator built from the official specification. It's similar to, but more maintained than msexcel-builder mentioned in the other answer.

// Require library
var excel = require('excel4node');

// Create a new instance of a Workbook class
var workbook = new excel.Workbook();

// Add Worksheets to the workbook
var worksheet = workbook.addWorksheet('Sheet 1');
var worksheet2 = workbook.addWorksheet('Sheet 2');

// Create a reusable style
var style = workbook.createStyle({
  font: {
    color: '#FF0800',
    size: 12
  },
  numberFormat: '$#,##0.00; ($#,##0.00); -'
});

// Set value of cell A1 to 100 as a number type styled with paramaters of style
worksheet.cell(1,1).number(100).style(style);

// Set value of cell B1 to 300 as a number type styled with paramaters of style
worksheet.cell(1,2).number(200).style(style);

// Set value of cell C1 to a formula styled with paramaters of style
worksheet.cell(1,3).formula('A1 + B1').style(style);

// Set value of cell A2 to 'string' styled with paramaters of style
worksheet.cell(2,1).string('string').style(style);

// Set value of cell A3 to true as a boolean type styled with paramaters of style but with an adjustment to the font size.
worksheet.cell(3,1).bool(true).style(style).style({font: {size: 14}});

workbook.write('Excel.xlsx');
mikemaccana
  • 110,530
  • 99
  • 389
  • 494
  • Hi mikemaccana , where should i use this code. do i have to use this code in controller or any schema code. can you answer this question:https://stackoverflow.com/questions/44369082/excel-download-is-not-working-in-mean-stack-app/44373532#44373532 – Vinoth Jun 06 '17 at 07:41
  • I receive an error Error: Cannot find module 'excel4node', and installed it with npm install before used – Raz Jan 18 '18 at 10:29
  • 1
    @raz You should ask this as a question. – mikemaccana Jan 18 '18 at 12:40
  • @mikemaccana is there any posssible way to export array list. – Vinoth Jul 27 '18 at 12:32
  • @vinoth I'm not sure what you're asking, but maybe ask a question and tag it `node` `excel4node` `excel` and soemone will help? – mikemaccana Jul 27 '18 at 14:29
  • I have a set of array called "reportData". Where i need to pass this reportData value in above code to generate the excel contains the reportData value?. @mikemaccana – tamilselvan s Nov 08 '19 at 11:05
  • 1
    @tamilselvans Use an `array.forEach(value, index)` and `worksheet.cell(column, row).string(value)`. Bette yet read the docs! – mikemaccana Nov 08 '19 at 11:09
  • Is excel4node still maintained? Their last commit is from 14 months ago and they have 109 opened issues on github – 7hibault Jul 02 '20 at 13:49
  • @mikemaccana how would I then open this workbook in Excel from node.js? – Alex Morrison Feb 25 '21 at 15:57
  • @AlexMorrison generally I imagine you'd want the user to download the file, but if you want to start excel from node, you'd run it the same way you'd run any other command from node. – mikemaccana Feb 25 '21 at 17:07
  • @mikemaccana sorry yes, I should have been a little clearer. How would I get node to prompt the user to download/open the excel workbook? – Alex Morrison Feb 26 '21 at 08:13
  • @AlexMorrison have node show a web page, link to the file, with the `download` option on the link turned on. You should ask this as a question though - it's an entirely separate matter. – mikemaccana Feb 26 '21 at 12:29
  • @mikemaccana ok I've asked this as a question here if you could take a look, thanks: https://stackoverflow.com/questions/66419549/open-excel4node-workbook-with-node-js – Alex Morrison Mar 01 '21 at 09:30
62

I just figured a simple way out . This works -

Just create a file with Tabs as delimiters ( similar to CSV but replace comma with Tab ). Save it with extension .XLS . The file can be opened in Excel .

Some code to help --

var fs = require('fs');
var writeStream = fs.createWriteStream("file.xls");

var header="Sl No"+"\t"+" Age"+"\t"+"Name"+"\n";
var row1 = "0"+"\t"+" 21"+"\t"+"Rob"+"\n";
var row2 = "1"+"\t"+" 22"+"\t"+"bob"+"\n";

writeStream.write(header);
writeStream.write(row1);
writeStream.write(row2);

writeStream.close();

This creates the file in XLS file format . It doesnt work if you try XLSX instead of XLS .

geeky_monster
  • 8,672
  • 18
  • 55
  • 86
  • 5
    Why not use commas and create a CSV file with node and then import it into Excel? This way Excel can do its thing and create the xls/xlsx file properly. – BrandonKowalski Jul 03 '13 at 14:43
  • I am providing a hosted service for clients . There will be lot of files generated as reports per day . I cant ask clients to export these files manually everytime . – geeky_monster Jul 03 '13 at 14:55
  • 1
    Ah gotcha. Neat fix you found however. – BrandonKowalski Jul 03 '13 at 14:58
  • 1
    In order to also support special characters, i made a simple wrapper with oh-csv https://github.com/SimpliField/oh-csv#excel-compatible-csv see http://stackoverflow.com/questions/6588068/which-encoding-opens-csv-files-correctly-with-excel-on-both-mac-and-windows – nfroidure Jun 27 '14 at 12:27
  • @JamaicaGeek: +1 to the answer and Thanks. ! – Pritam Mar 17 '15 at 11:49
  • Interesting answer which saved my time when i am working on the same after 2yrs of your update @JamaicaGeek ;) Thank you so much. 2 doubts, 1. writeStream.write is not working for rows at present. 2. How to deal with html inside xls formats. It would also be helpful, if anybody can suggest an better advanced library for doing this in simplest way :) – Mithun Shreevatsa Sep 18 '15 at 09:30
  • If I want to append data, what should I do? – Imam Abdul Mahmudi Oct 15 '15 at 03:05
  • 1
    how could I create some sheets? – Vinh.TV Jul 13 '16 at 08:13
  • @Vinh.TV - Sheets wont be possible to create via this method. Please see the alternate answers below to see how it can be done. – geeky_monster Jul 16 '16 at 03:50
  • 9
    "This creates the file in XLS file format." No it doesn't. It's still a CSV file and not capable of doing excel things,eg, multiple worksheets. – mikemaccana Mar 10 '17 at 15:03
  • 1
    2 problems you will encounter using the above method: 1. broken columns when your cells include quote character or new line 2. encoding issues when importing to Excel on Mac (you must include correct BOM `decodeURIComponent("%EF%BB%BF")` and encode using UTF16LE – Maciej Jankowski Apr 27 '17 at 17:06
  • how can i append in a loop like for(var i=0;i<10;i++){ // something for append into existing excel file } – kumbhani bhavesh Jan 03 '18 at 12:20
  • 7
    This does not answer the question at all, as it is not an excel file. – Darryn Hosking Aug 15 '18 at 06:16
  • this will screw upp any testnumber starting with zeros, (very common in phonenumbers), generally this is a poor idea, if you have to go down this path the problems with zeores can be solved using a singe quotemark (the same as in normal excelfiles) – Griffin Apr 12 '20 at 09:32
27

Although this question has several answers, they may now be a little dated.

New readers may prefer to consider the xlsx or "sheetsJS" package, which now seems to now be by far the most popular node package for this use case.

The current top answer recommends excel4node , which does look quite good - but the latter package seems less maintained (and far less popular) than the former.

Answering the question directly, using xlsx:

const XLSX = require('xlsx');

/* create a new blank workbook */
const wb = XLSX.utils.book_new();

// Do stuff, write data
//
//

// write the workbook object to a file
XLSX.writeFile(workbook, 'out.xlsx');
defraggled
  • 1,014
  • 11
  • 13
  • For some people excel4node will be easier to grasp, especially if you come from the JQuery world were you chain things. But JQuery is dying for a good reason and XLSX is a much cleaner way of doing things, and gives alot more control. – Griffin Apr 06 '21 at 14:02
  • 1
    I lost many hours trying to understand why it messed up my excel styles, only to find that the free community edition of sheetjs does not support styles. You have to buy the pro that does not even have a public price. – PA. Jan 19 '23 at 18:37
25

Use msexcel-builder. Install it with:

npm install msexcel-builder

Then:

// Create a new workbook file in current working-path 
var workbook = excelbuilder.createWorkbook('./', 'sample.xlsx')

// Create a new worksheet with 10 columns and 12 rows 
var sheet1 = workbook.createSheet('sheet1', 10, 12);

// Fill some data 
sheet1.set(1, 1, 'I am title');
for (var i = 2; i < 5; i++)
  sheet1.set(i, 1, 'test'+i);

// Save it 
workbook.save(function(ok){
  if (!ok) 
    workbook.cancel();
  else
    console.log('congratulations, your workbook created');
});
mikemaccana
  • 110,530
  • 99
  • 389
  • 494
Hesham Yassin
  • 4,341
  • 2
  • 21
  • 23
  • 3
    Can I pipe the result file to a Response object instead of saving to a disk? – lvarayut Jan 23 '15 at 04:57
  • sure, try npm request. – Hesham Yassin Jul 16 '16 at 08:53
  • 4
    This is an excellent answer (unlike the current marked answer, which doesn't create an Excel file at all) but `mxexcel-builder` hasn't had any updates for four years. I've added an answer using `excel4node` below. – mikemaccana Mar 20 '17 at 14:22
  • Hi Hesham Yassin, can you answer this question:https://stackoverflow.com/questions/44369082/excel-download-is-not-working-in-mean-stack-app/44373532#44373532 – Vinoth Jun 06 '17 at 07:40
  • I am getting this warning in console when run their sample code from npm: `(node:11702) [DEP0013] DeprecationWarning: Calling an asynchronous function without callback is deprecated.` – Mathew John Aug 18 '18 at 06:42
  • This example code is giving me "Invalid character in name" – CodingLittle Feb 26 '20 at 13:11
17

You should check ExcelJS

Works with CSV and XLSX formats.

Great for reading/writing XLSX streams. I've used it to stream an XLSX download to an Express response object, basically like this:

app.get('/some/route', function(req, res) {
  res.writeHead(200, {
    'Content-Disposition': 'attachment; filename="file.xlsx"',
    'Transfer-Encoding': 'chunked',
    'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
  })
  var workbook = new Excel.stream.xlsx.WorkbookWriter({ stream: res })
  var worksheet = workbook.addWorksheet('some-worksheet')
  worksheet.addRow(['foo', 'bar']).commit()
  worksheet.commit()
  workbook.commit()
}

Works great for large files, performs much better than excel4node (got huge memory usage & Node process "out of memory" crash after nearly 5 minutes for a file containing 4 million cells in 20 sheets) since its streaming capabilities are much more limited (does not allows to "commit()" data to retrieve chunks as soon as they can be generated)

See also this SO answer.

Maxime Pacary
  • 22,336
  • 11
  • 85
  • 113
9

XLSx in the new Office is just a zipped collection of XML and other files. So you could generate that and zip it accordingly.

Bonus: you can create a very nice template with styles and so on:

  1. Create a template in 'your favorite spreadsheet program'
  2. Save it as ODS or XLSx
  3. Unzip the contents
  4. Use it as base and fill content.xml (or xl/worksheets/sheet1.xml) with your data
  5. Zip it all before serving

However I found ODS (openoffice) much more approachable (excel can still open it), here is what I found in content.xml

<table:table-row table:style-name="ro1">
    <table:table-cell office:value-type="string" table:style-name="ce1">
        <text:p>here be a1</text:p>
    </table:table-cell>
    <table:table-cell office:value-type="string" table:style-name="ce1">
        <text:p>here is b1</text:p>
    </table:table-cell>
    <table:table-cell table:number-columns-repeated="16382"/>
</table:table-row>
Maciej Jankowski
  • 2,794
  • 3
  • 26
  • 33
  • 2
    Learning the OOXML is a non-trivial task. Also using a different file format isn't an answer to the question - this would be better as a comment. – mikemaccana Mar 10 '17 at 15:10
9

Using fs package we can create excel/CSV file from JSON data.

Step 1: Store JSON data in a variable (here it is in jsn variable).

Step 2: Create empty string variable(here it is data).

Step 3: Append every property of jsn to string variable data, while appending put '\t' in-between 2 cells and '\n' after completing the row.

Code:

var fs = require('fs');

var jsn = [{
    "name": "Nilesh",
    "school": "RDTC",
    "marks": "77"
   },{
    "name": "Sagar",
    "school": "RC",
    "marks": "99.99"
   },{
    "name": "Prashant",
    "school": "Solapur",
    "marks": "100"
 }];

var data='';
for (var i = 0; i < jsn.length; i++) {
    data=data+jsn[i].name+'\t'+jsn[i].school+'\t'+jsn[i].marks+'\n';
 }
fs.appendFile('Filename.xls', data, (err) => {
    if (err) throw err;
    console.log('File created');
 });

Output

Nilesh Pawar
  • 655
  • 7
  • 12
4

Or - build on @Jamaica Geek's answer, using Express - to avoid saving and reading a file:

  res.attachment('file.xls');

  var header="Sl No"+"\t"+" Age"+"\t"+"Name"+"\n";
  var row1 = [0,21,'BOB'].join('\t')
  var row2 = [0,22,'bob'].join('\t');

  var c = header + row1 + row2;
  return res.send(c);
kumbhani bhavesh
  • 2,189
  • 1
  • 15
  • 26
tmanolatos
  • 932
  • 10
  • 16
  • 4
    Unfortunately this is not a good idea. your data will likely break such naive code: Problems you will encounter using the above method: 1. broken columns when your cells include quote character or a new line ; and 2. encoding issues when importing to Excel on Mac (you must include correct BOM decodeURIComponent("%EF%BB%BF") and encode using UTF16LE. I recommend using a proper library instead – Maciej Jankowski Apr 27 '17 at 17:10
4

install exceljs

npm i exceljs --save

import exceljs

var Excel = require('exceljs');
var workbook = new Excel.Workbook();

create workbook

var options = {
                filename: __dirname+'/Reports/'+reportName,
                useStyles: true,
                useSharedStrings: true
            };

            var workbook = new Excel.stream.xlsx.WorkbookWriter(options);

after create worksheet

var worksheet = workbook.addWorksheet('Rate Sheet',{properties:{tabColor:{argb:'FFC0000'}}});

in worksheet.column array you pass column name in header and array key pass in key

worksheet.columns = [
            { header: 'column name', key: 'array key', width: 35},
            { header: 'column name', key: 'array key', width: 35},
            { header: 'column name', key: 'array key', width: 20},

            ];

after using forEach loop append row one by one in exel file

array.forEach(function(row){ worksheet.addRow(row); })

you can also perfome loop on each exel row and cell

worksheet.eachRow(function(row, rowNumber) {
    console.log('Row ' + rowNumber + ' = ' + JSON.stringify(row.values));
});
row.eachCell(function(cell, colNumber) {
    console.log('Cell ' + colNumber + ' = ' + cell.value);
});
rajpoot rehan
  • 435
  • 5
  • 14
3

Use exceljs library for creating and writing into existing excel sheets.

You can check this tutorial for detailed explanation.

link

Seenu69
  • 1,041
  • 2
  • 15
  • 33
1

First parameter is the source file

Second parameter is the separator

Third parameter is the resulting file (*.xlsx)

Attention: to increase node heap use: node --max-old-space-size=4096 index.js

const fs = require('fs');
var xl = require('excel4node');
const data = fs.readFileSync(process.argv[2], 'utf-8');
const lines = data.split(/\r?\n/);
const linesFromOne = [null].concat(lines);
var wb = new xl.Workbook();
var ws = wb.addWorksheet('Planilha 1');
for (let j=1;j<=linesFromOne.length-1;j++){             
  // Create a reusable style
  var style = wb.createStyle({
    font: {
      color: '#050000',
      size: 12,
    },

  });

    pieces = linesFromOne[j].split(process.argv[3])
    pieces.forEach((element, index) =>{
    ws.cell(j, index+1).string(element)
    .style(style);
    });

} 

wb.write(process.argv[4]);