Easy Ways to Download Any File From Node.js Server Using Express

Robin
April 30, 2022

There are multiple ways to download files Using Express from the Node.js application. You can download any type of file like image, text, pdf, etc following the same method.

Methods to let users download files from an Express server are:

  1. Use fs.readFile() method to read the file. Then set Content-Type and Content-Disposition header and finally send the file with res.send() method. (Not recommended)
  2. Stream the file using fs.createReadStream() method and set Content-Type and Content-Disposition header to the response. Finally, return the stream with the pipe() method.
  3. You can use res.download() the built-in method of Express to download any file from your server.
  4. You can use another built-in method of Express res.attachment() to allow your users to download files. Even though it might look like the res.download() method but there are some differences.

In this article, I will show you all these methods with examples to download any type of file from an Express server.

Also Read: Best Guide to Download File Using Node.js (HTTPS Module)

Before starting this lesson, you need to set up your Node.js and Express project using the following commands.

npm init -y

Initialize your Node.js project inside a folder. This command will create a package.json file.

npm install express dotenv

Install express and dotenv packages as dependencies. I am using dotenv package to load environment variables to my express server.

npm install --save-dev nodemon

I have installed nodemon package as a dev dependency. It will start my server automatically when I update my code while developing the server.

const { config } = require('dotenv');
const express = require('express');

const app = express();

// Loading environment variables
config();

app.get('/', (req, res) => {
    res.send('Hello World!');
});

const PORT = process.env.PORT || 5000;

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

This is a basic setup for an Express server. Now you can add your routes to it.

  "scripts": {
    "start": "node app.js",
    "dev": "nodemon app.js"
  },

To start the server, add these scripts to your package.json file. Now, you can spin up the development server using dev script. It will use nodemon package.

But if you want to use TypeScript, follow our complete guide on the best TypeScript setup with Express and Node.js projects.

1. Download Files Using fs.readFile() Method

Even though it is not a recommended way to download files from an Express server. Because it has some drawbacks if the file size is large.

I am showing you this first so that you can understand the difference between other methods. Next, I will show you a better alternative to this method.

const fs = require('fs');

app.get('/sendfile', (req, res) => {
    const filePath = `${__dirname}/download/javascript.pdf`;

    fs.readFile(filePath, (err, file) => {
        if (err) {
            console.log(err);
            return res.status(500).send('Could not download file');
        }

        res.setHeader('Content-Type', 'application/pdf');
        res.setHeader('Content-Disposition', 'inline; filename="js.pdf"');

        res.send(file);
    });
});

In this example, I have created a /sendfile route. When a user visits this route, it will download the javascript.pdf file which is present inside the download folder.

First, call fs.readFile() method to read the file. This method accepts 2 arguments. The first one is the file path and the second one is a callback function.

Inside the callback function, you will receive error if any, and the file. You can handle your error and send a response accordingly.

If there is no error, set some headers to the res object. I am setting the Content-Type header application/pdf because I am trying to download a pdf file. If you want to download a different type of file then set its value according to your file type.

For images, image/png, image/jpeg etc. You can see a list of content-type header values here. Learn more about the content-type header.

Next, you have to set the Content-Disposition header. This header tells the browser how it should handle a file. You can set 2 values for it inline or attachment.

res.setHeader('Content-Disposition', 'inline; filename="js.pdf"');
res.setHeader('Content-Disposition', 'attachment; filename="js.pdf"');

If you set inline then the browser will display the file in a browser tab as a part of a web page. But if you set attachment then the browser will start downloading the file without showing it.

The inline value is mostly useful for pdf files. You can show file content inside the browser before downloading.

Display pdf files in the browser using Express in Node.js

You can also pass a filename. This way, when a user downloads the file this will be the name of that downloaded file.

Finally, after setting these headers, you have to send the file using res.send() method. That’s it, now a user can download the javascript.pdf file.

Disadvantages

The disadvantage of this method is that fs.readFile() method will read the complete file in the memory before sending it to a user.

It will read and store the complete file in the memory for each request. Therefore, if the file size is large, it will take time to read the file. A user has to wait for a long time.

The much bigger problem is that storing a large file in memory will reduce your website performance. Because other parts of your application will have less memory.

That’s why you should avoid this method. Instead, you can stream your files using our next technique.

2. Stream Files Using fs.createReadStream() Method

By streaming means, you can read and send a file into smaller pieces. In this way, you don’t have to store the entire file in memory.

The Express server will read a small portion of a file and send it to the user. Then it will read another small part and send it. This way server will send the entire file.

Another advantage of this technique is your users don’t have to wait a long file to read the full file like the previous method. Whenever serve sends a portion of the file browser will display or download that portion.

So, it’s a much better user experience.

const fs = require('fs');

app.get('/stream', async (req, res) => {
    const filePath = `${__dirname}/download/javascript.pdf`;

    const stream = fs.createReadStream(filePath);

    res.setHeader('Content-Type', 'application/pdf');
    res.setHeader('Content-Disposition', 'inline; filename="js.pdf"');

    stream.pipe(res);
});

In this example, I am creating a “/stream” route. It will download the same javascript.pdf file. But this time, I will call fs.createReadStream() method with the file path.

This method will return a read stream. I am storing it in the stream variable.

You also have to set Content-Type and Content-Disposition header to let the browser know what it should do with the file.

Finally, I will call the pipe() method on the returned read stream. Pass the res object to the pipe() method.

Also Read: Perfect Ways to Serve Static Files in Express and Node.js

3. Download Files Using res.download() Method

If you don’t want to stream your file manually then you can use the download() method provided by Express.

app.get('/download', (req, res) => {
    const filePath = `${__dirname}/download/javascript.pdf`;

    res.download(filePath);
});

Here, I am creating a “/download” route. Inside your route callback function, you can call res.download() method by passing the file path to it.

You don’t have to set any response headers. This method will automatically set the necessary headers for you.

The only difference is that you can not open a file inside a browser tab using this method. When you use the download() method, the browser will always start to download the file without displaying it.

This method also accepts 2 more optional arguments. Using these arguments you can set the filename for the downloaded file. When a user downloads the file, this name will be used there.

app.get('/download', (req, res) => {
    const filePath = `${__dirname}/download/javascript.pdf`;

    res.download(filePath, 'js.pdf');
});

You can also pass a callback function to handle the error if there is any. This callback function will give the error as its argument.

app.get('/download', (req, res) => {
    const filePath = `${__dirname}/download/javascript.pdf`;

    res.download(filePath, (err) => {
        if (err) {
            console.log(err);
            res.status(500).send('Could not download file');
        }
    });
});

You can also use all the 3 arguments together i.e. file path, filename, and the callback function.

app.get('/download', (req, res) => {
    const filePath = `${__dirname}/download/javascript.pdf`;

    res.download(filePath, 'js.pdf', (err) => {
        if (err) {
            console.log(err);
            res.status(500).send('Could not download file');
        }
    });
});

4. Download Files Using res.attachment() Method

You can also use res.attachment() method to download a file in Express. This method only accepts one argument i.e. file path.

It always set the Content-Disposition header to attachment and set the filename according to the name in the path. You can not provide any custom filename.

It also set the Content-Type header according to the file type in the path.

app.get('/attachment', (req, res) => {
    const filePath = `${__dirname}/download/javascript.pdf`;

    res.attachment(filePath).send();
});

In the “/attachment” route, I am calling res.attachment() method with the file path. You can also notice that I am calling send() method after the attachment() method.

You have to use send() method in order to download the file.

Conclusion

Express makes it easy to download a file. You can add an endpoint to set up your downloading logic.

You are not limited to using pdf files only. You can use the above methods to download any type of file in the Express application.

I have explained multiple ways in detail so that you can set up an endpoint to download files using Express from a Node.js server.

I hope it was helpful. Thank you so much for reading. Happy coding!

Related Posts