How to stream file downloads in Node.js

Streaming file downloads is essential for Node.js applications serving large files efficiently without consuming excessive memory. As the creator of CoreUI with over 11 years of Node.js development experience since 2014, I’ve optimized file serving in numerous enterprise applications. The most effective solution is to use Node.js streams with createReadStream to pipe files directly to the response. This approach handles files of any size efficiently while maintaining low memory usage.

Use createReadStream and pipe to stream file downloads in Node.js.

const express = require('express')
const fs = require('fs')
const path = require('path')

const app = express()

app.get('/download/:filename', (req, res) => {
  const filename = req.params.filename
  const filepath = path.join(__dirname, 'files', filename)

  // Check if file exists
  if (!fs.existsSync(filepath)) {
    return res.status(404).json({ error: 'File not found' })
  }

  // Get file stats
  const stat = fs.statSync(filepath)

  // Set headers
  res.setHeader('Content-Disposition', `attachment; filename="${filename}"`)
  res.setHeader('Content-Type', 'application/octet-stream')
  res.setHeader('Content-Length', stat.size)

  // Create read stream and pipe to response
  const readStream = fs.createReadStream(filepath)

  readStream.on('error', (error) => {
    console.error('Stream error:', error)
    if (!res.headersSent) {
      res.status(500).json({ error: 'Error streaming file' })
    }
  })

  readStream.pipe(res)
})

The createReadStream() creates a readable stream from the file without loading it into memory. The pipe() method automatically handles backpressure and data flow to the response. Setting Content-Disposition triggers browser download behavior with the specified filename. Error handling ensures graceful failure if the stream encounters issues. This approach scales to files of any size without memory concerns.

Best Practice Note

This is the same streaming approach we use in CoreUI backend systems for efficient file serving. For enhanced security, validate and sanitize filenames to prevent path traversal attacks. Consider implementing range request support for resumable downloads and media streaming by checking the Range header and using createReadStream with start and end options.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author

Subscribe to our newsletter
Get early information about new products, product updates and blog posts.
How to show or hide elements in React? A Step-by-Step Guide.
How to show or hide elements in React? A Step-by-Step Guide.

What is the difference between sort and toSorted in JavaScript?
What is the difference between sort and toSorted in JavaScript?

What is globalThis in JavaScript?
What is globalThis in JavaScript?

How to Open All Links in New Tab Using JavaScript
How to Open All Links in New Tab Using JavaScript

Answers by CoreUI Core Team