Express File Upload Middleware
express-fileupload is a straightforward middleware for the Express.js framework, designed to simplify handling multipart/form-data for file uploads. It acts as a wrapper around the `Busboy` parser, exposing uploaded files via `req.files` for easy access. The current stable version is 1.5.2, with minor releases and bug fixes occurring relatively frequently to address issues and introduce small features like custom loggers or hash algorithm options. Key differentiators include its simple API that provides a `mv()` function for relocating uploaded files, direct access to file properties (name, mimetype, size, data buffer), and an option to utilize temporary files on disk instead of memory, which is beneficial for handling large uploads efficiently. The middleware is actively maintained and offers robust handling of file streams.
Common errors
-
TypeError: file.destroy is not a function
cause An issue in older versions where the `file.destroy` method was incorrectly implemented or missing for certain scenarios, preventing proper cleanup of temporary file streams.fixUpgrade `express-fileupload` to v1.4.2 or newer. This version specifically addresses the `TypeError: file.destroy is not a function` error. -
TypeError - Cannot read properties of undefined (reading 'includes') in lib/isEligibleRequest.js
cause This error typically occurred in older versions when the middleware attempted to check request headers or methods on an undefined object, often due to malformed requests or specific edge cases.fixUpdate `express-fileupload` to v1.4.3 or a later version. This release includes a fix for the `TypeError` related to `isEligibleRequest.js`. -
Unhandled promise rejection warning
cause In versions prior to v1.2.1, certain asynchronous operations within the middleware, particularly related to limit handlers or file processing, might not have properly caught or handled promise rejections, leading to unhandled promise warnings in Node.js.fixUpgrade `express-fileupload` to v1.2.1 or newer. This version includes updates to better handle promise rejections and prevent unhandled promise warnings. -
Error: Request aborted
cause While not a direct error message *from* express-fileupload, users might encounter this in their server logs when a client prematurely disconnects during a large upload, or when file size limits are exceeded and the connection is terminated by the server without proper cleanup or error propagation in older versions.fixEnsure `express-fileupload` is updated to at least v1.4.2, which included stricter request checks and improved handling of abortions on limit exceeding (preventing `next()` from being called after abortion). Implement client-side retry logic and server-side logging for aborted requests.
Warnings
- breaking Node.js versions prior to 12 are no longer supported since v1.3.1. Applications running on older Node.js runtimes will encounter errors or unexpected behavior.
- breaking The behavior of the `md5` property on uploaded file objects has changed multiple times across versions. It was a checksum (before v1.0.0), then a function (v1.0.0-1.1.1), then reverted to a checksum (v1.1.1-1.5.1), and from v1.5.1, it's still a checksum but generated with a configurable `hashAlgorithm` while the property name remains `md5` for backward compatibility.
- gotcha Older versions (pre-1.5.2) could experience possible conflicts for temporary file names, leading to data corruption or incorrect file handling, especially under high concurrency.
- gotcha Prototype pollution vulnerability was fixed in v1.3.1. This type of vulnerability could allow an attacker to inject arbitrary properties into object prototypes, potentially leading to remote code execution or denial of service.
- gotcha Handling of file names with special characters (e.g., non-ASCII) was problematic in versions prior to v1.4.1, potentially causing upload failures or incorrect file paths.
Install
-
npm install express-fileupload -
yarn add express-fileupload -
pnpm add express-fileupload
Imports
- fileUpload
const fileUpload = require('express-fileupload');import fileUpload from 'express-fileupload';
- fileUpload.options
app.use(fileUpload.useTempFiles = true);
app.use(fileUpload({ useTempFiles: true, tempFileDir: '/tmp/' })); - UploadedFile
import { FileUpload } from 'express-fileupload';// In a TypeScript project: import { UploadedFile } from 'express-fileupload';
Quickstart
import express from 'express';
import fileUpload from 'express-fileupload';
import path from 'path';
import { promises as fs } from 'fs';
const app = express();
const PORT = process.env.PORT || 3000;
const UPLOAD_DIR = path.join(process.cwd(), 'uploads');
// Create upload directory if it doesn't exist
fs.mkdir(UPLOAD_DIR, { recursive: true }).catch(console.error);
// Middleware: Enable file uploads with temporary files
app.use(fileUpload({
useTempFiles: true,
tempFileDir: '/tmp/', // Ensure this directory exists and is writable
limits: { fileSize: 50 * 1024 * 1024 } // 50MB limit
}));
app.post('/upload', async (req, res) => {
if (!req.files || Object.keys(req.files).length === 0) {
return res.status(400).send('No files were uploaded.');
}
// 'foo' is the name of the input field in the form
const uploadedFile = req.files.foo;
// Check if uploadedFile is an array (multiple files with same name attribute)
// For simplicity, assume single file upload with 'foo' name.
if (Array.isArray(uploadedFile)) {
return res.status(400).send('Multiple files for a single input field not supported in this example.');
}
const uploadPath = path.join(UPLOAD_DIR, uploadedFile.name);
try {
await uploadedFile.mv(uploadPath);
res.send(`File uploaded to ${uploadPath}`);
} catch (err) {
console.error(err);
res.status(500).send(err.message);
}
});
app.get('/', (req, res) => {
res.send(`
<h1>Upload a File</h1>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="foo" />
<input type="submit" value="Upload" />
</form>
`);
});
app.listen(PORT, () => {
console.log(`Server listening on port ${PORT}`);
console.log(`Uploads will be saved to ${UPLOAD_DIR}`);
});