How to Read and Write CSV Files Using Node.js and Express
Tags: javascript, beginners
Published: 2022-02-22 16:08:44

---
title: How to Read and Write CSV Files Using Node.js and Express
published: true
date: 2022-02-22 10:35:58 UTC
tags: Javascript,Beginners
canonical_url: https://blog.shahednasser.com/how-to-read-and-write-csv-files-using-node-js-and-express/
cover_image: https://blog.shahednasser.com/static/5d307db98559d10d7109a83b8373bfd7/How-to-Read-and-Write-CSV-Files-Using-Node.js-and-Express.jpg
---

_This article was originally published on [my personal blog](https://blog.shahednasser.com/how-to-read-and-write-csv-files-using-node-js-and-express/)._

Node.js can be used to build a variety of apps and websites. It's most popularly used with [Express](https://expressjs.com) to create a server for your websites and apps.

In this tutorial, you'll learn how you can read and write CSV files using Node.js and Express. You can find the full code for this tutorial in[this GitHub Repository](https://github.com/shahednasser/node-csv-tutorial).

## Project Setup

You'll start by setting up the server with NPM.

Run the following command to create a new directory and initialize the project with NPM:

```
mkdir node-csv
npm init -y
```

Then, you need to install the dependencies needed for the project:

```
npm i express body-parser nodemon
```

This will install `express` to create a server, `body-parser` to parse the body of the requests, and `nodemon` to make sure that the server restarts whenever there are new changes in the files.

After that, create `index.js` with the following content:

```
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
const port = 3000

app.use(bodyParser.json())
app.use(express.static('public'))

app.listen(port, () => {
  console.log(`App listening on port ${port}`)
})
```

This will initialize your server.

Finally, add the `start` script command in `package.json`:

```
"scripts": {
    "start": "nodemon index.js"
},
```

Now, you can start the server by running the following command:

```
npm start
```

This will start the server on `localhost:3000`.

## Write CSV Files

The first part of this tutorial will go over how you can write CSV files.

For this, you'll use the CSV Stringify library that takes a set of data and turns it into a string in the CSV format. You can then use the string to write a CSV file.

In this tutorial, you'll create a page where the user can dynamically create a table to be transformed into a CSV file that they can download.

Start by installing the necessary dependency for this functionality:

```
npm i csv-stringify
```

Create the file `public/create.html` with the following content:

```
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" 
    integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
  <link href="https://unpkg.com/tabulator-tables/dist/css/tabulator.min.css" rel="stylesheet">
  <title>Create CSV</title>
</head>
<body>
  <div class="container py-4">
    <h1>Create CSV</h1>
    <h2>Add Columns</h2>
    <input type="text" name="column" id="columnName" class="form-control" placeholder="Column Name" />
    <button class="btn btn-primary mt-1" id="addColumn">Add</button>
    <h2 class="mt-3">Column Data</h2>
    <button class="btn btn-primary mb-3" id="addRow">Add Row</button>
    <div id="csvTable"></div>
    <button class="btn btn-primary mt-3" id="submitForm">Create CSV</button>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" 
    integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
  <script type="text/javascript" src="https://unpkg.com/tabulator-tables/dist/js/tabulator.min.js"></script>
  <script>
    const columnNameInput = document.getElementById('columnName');
    const addColumnButton = document.getElementById('addColumn');
    const addRowButton = document.getElementById('addRow');
    const submitFormButton = document.getElementById('submitForm');

    const table = new Tabulator("#csvTable", {
      height:"300px",
      data: [], //assign data to table
      movableColumns: true, 
      addRowPos: "bottom",
    });

    addColumnButton.addEventListener('click', () => {
      const name = columnNameInput.value ? columnNameInput.value.trim() : '';
      if (!name) {
        alert("Please add a name");
        return;
      }

      table.addColumn({title: name, field: name.toLowerCase(), editableTitle: true, editor: true});
      columnNameInput.value = '';
    });

    addRowButton.addEventListener('click', () => {
      table.addRow({});
    });

    submitFormButton.addEventListener('click', () => {
      const data = table.getData();

      fetch('/create', {
        method: 'POST',
        body: JSON.stringify({
          data
        }),
        headers: {
          'Content-Type': 'application/json'
        }
      })
      .then((response) => response.blob())
      .then((blob) => {
        const fileURL = URL.createObjectURL(blob)
        const a = document.createElement('a')
        a.href = fileURL
        a.download = "file.csv"
        a.click()
      })
      .catch((e) => {
        console.error(e)
        alert(e.message)
      })
    })
  </script>
</body>
</html>
```

This page will allow the user to create a CSV file. For simplicity, you're using [Bootstrap](https://getbootstrap.com) for easy styling and [Tabulator](http://tabulator.info) to easily create a table with modifiable columns and rows.

You show the user an input to add columns with a name, and a button to add rows. After the user creates the CSV file using the table. They can click on the "Create CSV" button. This will take the data from the table and send a `POST` request to the `create` endpoint (which you'll create next) with the data. Then, the received file will be downloaded.

Next, you'll create the `create` endpoint. Open `index.js` and add the following `require` statement at the beginning of the file:

```
const fs = require('fs')
const stringify = require('csv-stringify').stringify
```

You'll use `fs` to create the CSV file and `stringify` from the `csv-stringify` library.

Next, add the following new endpoint to your server:

```
app.post('/create', (req, res) => {
  const data = req.body.data

  if (!data || !data.length) {
    return res.status(400).json({success: false, message: 'Please enter at least 1 row'})
  }

  stringify(data, {
    header: true
  }, function (err, str) {
    const path = './files/' + Date.now() + '.csv'
    //create the files directory if it doesn't exist
    if (!fs.existsSync('./files')) {
      fs.mkdirSync('./files')
    }
    fs.writeFile(path, str, function (err) {
      if (err) {
        console.error(err)
        return res.status(400).json({success: false, message: 'An error occurred'})
      }

      res.download(path, 'file.csv')
    })
  })
})
```

This will first validate the data sent. Then, you'll use the `stringify` function to create the CSV string. This function takes the data to be stringified as the first parameter, an object of [options](https://csv.js.org/stringify/options/) as the second parameter, and a callback function as the third.

The `header` option makes sure to include the column names as the header of the CSV file.

In the callback function, you create a file using `fs` in the directory `files` using `writeFile`. The file will contain the CSV string created by `stringify`. In the callback function of `writeFile` you return the CSV file for download.

Now, if you run the server (if it's not already running) and go to `localhost:3000/create.html` you'll see the page you created earlier in `public/create.html`. Try adding a few columns and rows into the table.

![How to Read and Write CSV Files Using Node.js and Express](https://backend.shahednasser.com/content/images/2022/02/Screen-Shot-2022-02-12-at-7.28.59-PM.png)

Once you're done, click the "Create CSV" button. This will send the data to the server at the `create` endpoint you created. Then, the endpoint will return a file for download which will then initiate a download in the user's browser.

## Read a CSV File

In this section, you'll learn how to read a CSV file in Node.js and Express. The user will upload a CSV file.

Then, you'll pass the file along to the server that will parse it and return the data in JSON format. You'll then use Tabulator to show the CSV file's data.

To parse a CSV file, you'll use [CSV Parse](https://csv.js.org/parse/). You'll also use Express Multer Middleware to handle file upload.

Start by downloading the necessary dependencies:

```
npm i multer csv-parse
```

N0w, create the file `public/read.html` with the following content:

```
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Read CSV</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" 
    integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
  <link href="https://unpkg.com/tabulator-tables/dist/css/tabulator.min.css" rel="stylesheet">
</head>
<body>
  <div class="container py-4">
    <h1>Read CSV</h1>
    <label for="file">Choose file to read</label>
    <input type="file" class="form-control" name="file" id="file" />
    <button class="btn btn-primary mt-2" id="submitFile">Read</button>
    <div class="mt-2" id="csvTable"></div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" 
    integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
  <script type="text/javascript" src="https://unpkg.com/tabulator-tables/dist/js/tabulator.min.js"></script>
  <script>
    const fileInput = document.getElementById('file')
    const submitFile = document.getElementById('submitFile')
    let file = null

    fileInput.addEventListener('change', function () {
      file = this.files[0]
    })

    submitFile.addEventListener('click', function () {
      if (!file || file.type !== 'text/csv') {
        alert('Please choose a CSV file')
        return
      }

      const formData = new FormData()
      formData.append('file', file)

      fetch('/read', {
        method: 'POST',
        body: formData
      })
      .then((response) => response.json())
      .then(({ data }) => {
        if (data.length) {
          const columns = data[0]
          const rows = data.splice(1).map((arr) => {
            const obj = {}
            columns.forEach((column, index) => {
              obj[column] = arr[index]
            })
            return obj
          })

          console.log(rows, columns)
          
          const table = new Tabulator("#csvTable", {
            height:"300px",
            data: rows,
            autoColumns: true
          });
        } else {
          alert('The CSV is empty')
        }
      })
      .catch((e) => alert(e.message))
    })
  </script>
</body>
</html>
```

Just like `create.html` this file uses Bootstrap for easy styling and Tabulator to easily show the CSV file in a table.

The page shows a file input for the user with a button to upload the CSV file. When the user chooses a file and clicks the button, the file is uploaded to the server at the endpoint `read` (which you'll create next). Then, using the data the server creates you'll show the data in a Tabulator table.

Now, you need to add the `read` endpoint.

In `index.js`, add the following require statements at the beginning of the file:

```
const parse = require('csv-parse').parse
const os = require('os')
const multer = require('multer')
const upload = multer({ dest: os.tmpdir() })
```

Notice that you also initialize multer and specify the destination as the `tmp` directory of the operating system. This is because you don't need to actually store the file anywhere for this tutorial.

Also, note that you'll need to use `fs` as well. So, if you didn't follow along with the previous section make sure to require it here as well.

Then, add the following new endpoint:

```
app.post('/read', upload.single('file'), (req, res) => {
  const file = req.file

  const data = fs.readFileSync(file.path)
  parse(data, (err, records) => {
    if (err) {
      console.error(err)
      return res.status(400).json({success: false, message: 'An error occurred'})
    }

    return res.json({data: records})
  })
})
```

You first read the file using `fs.readFileSync`. Then, you parse the file data using `parse` from `csv-parse`.

If an error occurs, you return an error message to the user. Otherwise, you return the data.

Run the server if it's not running already then go to `localhost:3000/read.html`. You'll see a file input with a button.

![How to Read and Write CSV Files Using Node.js and Express](https://backend.shahednasser.com/content/images/2022/02/Screen-Shot-2022-02-12-at-8.40.33-PM.png)

Choose a CSV file then click read. The file data will be displayed in a table using Tabulator.

![How to Read and Write CSV Files Using Node.js and Express](https://backend.shahednasser.com/content/images/2022/02/Screen-Shot-2022-02-12-at-8.52.52-PM.png)

## Conclusion

In this tutorial, you learned how you can read and write CSV files in Node.js and Express. You used the libraries [CSV Parse](https://csv.js.org/parse/) and [CSV Stringify](https://csv.js.org/stringify/) to do that. Please check out each of their documentation for better understanding of how it works and what more you can do with them.