DEV Community

Cover image for How to Read and Write CSV Files Using Node.js and Express
Shahed Nasser
Shahed Nasser

Posted on • Originally published at blog.shahednasser.com on

How to Read and Write CSV Files Using Node.js and Express

This article was originally published on my personal blog.

Node.js can be used to build a variety of apps and websites. It's most popularly used with Express 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 inthis GitHub Repository.

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
Enter fullscreen mode Exit fullscreen mode

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

npm i express body-parser nodemon
Enter fullscreen mode Exit fullscreen mode

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}`)
})
Enter fullscreen mode Exit fullscreen mode

This will initialize your server.

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

"scripts": {
    "start": "nodemon index.js"
},
Enter fullscreen mode Exit fullscreen mode

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

npm start
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

This page will allow the user to create a CSV file. For simplicity, you're using Bootstrap for easy styling and Tabulator 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
Enter fullscreen mode Exit fullscreen mode

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')
    })
  })
})
Enter fullscreen mode Exit fullscreen mode

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 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

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. You'll also use Express Multer Middleware to handle file upload.

Start by downloading the necessary dependencies:

npm i multer csv-parse
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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() })
Enter fullscreen mode Exit fullscreen mode

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})
  })
})
Enter fullscreen mode Exit fullscreen mode

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

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

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 and CSV 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.

Top comments (0)