CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-express-fileupload

Simple express file upload middleware that wraps around Busboy

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

index.mddocs/

Express File Upload

Express File Upload is a simple Express.js middleware that provides file upload functionality by wrapping around the Busboy library. It automatically parses multipart forms and makes uploaded files available through the req.files object with a clean, intuitive API.

Package Information

  • Package Name: express-fileupload
  • Package Type: npm
  • Language: JavaScript
  • Installation: npm install express-fileupload

Core Imports

const fileUpload = require('express-fileupload');

ESM:

import fileUpload from 'express-fileupload';

Basic Usage

const express = require('express');
const fileUpload = require('express-fileupload');

const app = express();

// Default options
app.use(fileUpload());

app.post('/upload', (req, res) => {
  if (!req.files || Object.keys(req.files).length === 0) {
    return res.status(400).send('No files were uploaded.');
  }

  // The name of the input field (i.e. "sampleFile") is used to retrieve the uploaded file
  let sampleFile = req.files.sampleFile;

  // Use the mv method to move the file to your desired upload directory
  sampleFile.mv('/path/to/upload/directory/filename.jpg', (err) => {
    if (err) return res.status(500).send(err);
    res.send('File uploaded!');
  });
});

Architecture

Express File Upload is built around several key components:

  • Middleware Factory: The main export creates Express middleware with customizable options
  • Multipart Processing: Uses Busboy internally to parse multipart/form-data requests
  • File Handling: Supports both memory-based and temporary file-based upload handling
  • File Objects: Each uploaded file becomes an object with properties and methods for easy manipulation
  • Configuration System: Extensive options for controlling upload behavior, limits, and file handling

Capabilities

Middleware Factory Function

Creates Express middleware for handling file uploads with extensive configuration options.

/**
 * Creates Express middleware for handling file uploads
 * @param {Object} options - Configuration options for file upload behavior
 * @returns {Function} Express middleware function (req, res, next) => void
 */
function fileUpload(options);

Usage Examples:

// Basic usage with default options
app.use(fileUpload());

// With custom options
app.use(fileUpload({
  limits: { fileSize: 50 * 1024 * 1024 }, // 50MB limit
  useTempFiles: true,
  tempFileDir: '/tmp/',
  debug: true
}));

// With advanced configuration
app.use(fileUpload({
  createParentPath: true,
  safeFileNames: true,
  preserveExtension: 4,
  abortOnLimit: true,
  responseOnLimit: 'File size limit has been reached',
  uploadTimeout: 120000, // 2 minutes
  hashAlgorithm: 'sha256'
}));

File Upload Options

Comprehensive configuration options for controlling upload behavior.

interface FileUploadOptions {
  /** Enable debug logging */
  debug?: boolean;
  /** Custom logger with .log() method */
  logger?: Object;
  /** Upload timeout in milliseconds */
  uploadTimeout?: number;
  /** Custom file handler function */
  fileHandler?: boolean | Function;
  /** Decode URI-encoded filenames */
  uriDecodeFileNames?: boolean;
  /** Sanitize unsafe characters in filenames */
  safeFileNames?: boolean | RegExp;
  /** Preserve file extensions during sanitization */
  preserveExtension?: boolean | number;
  /** Abort upload when size limit reached */
  abortOnLimit?: boolean;
  /** Response message for size limit violations */
  responseOnLimit?: string;
  /** Custom limit handler function */
  limitHandler?: Function;
  /** Create parent directories if they don't exist */
  createParentPath?: boolean;
  /** Parse nested form fields */
  parseNested?: boolean;
  /** Use temporary files instead of memory */
  useTempFiles?: boolean;
  /** Directory for temporary files */
  tempFileDir?: string;
  /** File permissions for temporary files */
  tempFilePermissions?: number;
  /** Hash algorithm for file checksums */
  hashAlgorithm?: string;
}

Default Values:

  • debug: false
  • logger: console
  • uploadTimeout: 60000 (60 seconds)
  • fileHandler: false
  • uriDecodeFileNames: false
  • safeFileNames: false
  • preserveExtension: false
  • abortOnLimit: false
  • responseOnLimit: 'File size limit has been reached'
  • limitHandler: false
  • createParentPath: false
  • parseNested: false
  • useTempFiles: false
  • tempFileDir: 'tmp' (relative to current working directory)
  • tempFilePermissions: 0o644
  • hashAlgorithm: 'md5'

File Object API

Each uploaded file becomes an object with properties and methods for file manipulation.

interface UploadedFile {
  /** Original filename */
  name: string;
  /** File content as Buffer (empty if useTempFiles is true) */
  data: Buffer;
  /** File size in bytes */
  size: number;
  /** File encoding */
  encoding: string;
  /** Path to temporary file (if useTempFiles is true) */
  tempFilePath: string;
  /** Whether file was truncated due to size limits */
  truncated: boolean;
  /** MIME type of the file */
  mimetype: string;
  /** File checksum using configured hash algorithm */
  md5: string;
  
  /**
   * Move file to specified location
   * @param {string} filePath - Destination file path
   * @param {Function} callback - Optional callback function
   * @returns {Promise|undefined} Promise if no callback provided
   */
  mv(filePath: string, callback?: Function): Promise<void> | undefined;
}

Usage Examples:

app.post('/upload', (req, res) => {
  const uploadedFile = req.files.myFile;
  
  // Access file properties
  console.log('Filename:', uploadedFile.name);
  console.log('Size:', uploadedFile.size);
  console.log('MIME type:', uploadedFile.mimetype);
  console.log('MD5 checksum:', uploadedFile.md5);
  
  // Move file using callback
  uploadedFile.mv('/uploads/' + uploadedFile.name, (err) => {
    if (err) return res.status(500).send(err);
    res.send('File uploaded successfully');
  });
});

// Using Promise-based approach
app.post('/upload-async', async (req, res) => {
  try {
    const uploadedFile = req.files.myFile;
    await uploadedFile.mv('/uploads/' + uploadedFile.name);
    res.send('File uploaded successfully');
  } catch (err) {
    res.status(500).send(err);
  }
});

Request Integration

The middleware automatically adds file objects to the Express request object.

interface Request {
  /** 
   * Object containing uploaded files, where keys are form field names 
   * and values are UploadedFile objects or arrays of UploadedFile objects
   */
  files: { [fieldName: string]: UploadedFile | UploadedFile[] } | null;
}

Usage Examples:

app.post('/single-upload', (req, res) => {
  // Single file upload
  const file = req.files.singleFile;
  // file is an UploadedFile object
});

app.post('/multi-upload', (req, res) => {
  // Multiple files with same field name
  const files = req.files.multipleFiles;
  if (Array.isArray(files)) {
    // files is an array of UploadedFile objects
    files.forEach(file => {
      console.log(file.name);
    });
  } else {
    // Single file (files is an UploadedFile object)
    console.log(files.name);
  }
});

app.post('/mixed-upload', (req, res) => {
  // Mixed upload with different field names
  const profilePic = req.files.profilePicture;
  const documents = req.files.documents; // Could be single file or array
  const avatar = req.files.avatar;
});

Busboy Integration

All Busboy configuration options can be passed through the options object for advanced multipart parsing control.

interface BusboyOptions {
  /** Field name size limit */
  fieldNameSize?: number;
  /** Field value size limit */
  fieldSize?: number;
  /** Number of non-file fields limit */
  fields?: number;
  /** File size limit per file */
  fileSize?: number;
  /** Number of files limit */
  files?: number;
  /** Number of parts limit */
  parts?: number;
  /** Header pairs limit */
  headerPairs?: number;
}

Usage Examples:

// Combine express-fileupload options with Busboy options
app.use(fileUpload({
  // Express-fileupload options
  useTempFiles: true,
  tempFileDir: '/tmp/',
  createParentPath: true,
  
  // Busboy options
  limits: {
    fileSize: 10 * 1024 * 1024, // 10MB per file
    files: 5, // Maximum 5 files
    fieldSize: 1024, // 1KB per field
    fields: 10 // Maximum 10 non-file fields
  }
}));

Error Handling

The middleware integrates with Express error handling and can generate errors for various conditions:

  • Invalid hash algorithms: When specified hashAlgorithm is not supported by the system
  • Invalid file permissions: When tempFilePermissions are outside acceptable range (0o600-0o777)
  • Upload timeouts: When files take longer than uploadTimeout to upload
  • File system errors: During file operations when using temporary files
  • Size limit violations: When abortOnLimit is true and limits are exceeded
// Error handling example
app.use(fileUpload({
  uploadTimeout: 60000,
  abortOnLimit: true,
  limits: { fileSize: 1024 * 1024 } // 1MB
}));

app.use((err, req, res, next) => {
  console.error('File upload error:', err);
  res.status(500).send('Upload failed');
});

Common Patterns

Temporary Files vs Memory

// Memory-based (default) - good for small files
app.use(fileUpload()); // Files stored in req.files[].data Buffer

// Temporary files - better for large files
app.use(fileUpload({
  useTempFiles: true,
  tempFileDir: '/tmp/'
})); // Files stored on disk, accessible via req.files[].tempFilePath

File Validation and Processing

app.post('/upload', (req, res) => {
  if (!req.files || !req.files.document) {
    return res.status(400).send('No file uploaded');
  }
  
  const file = req.files.document;
  
  // Validate file type
  if (!file.mimetype.startsWith('image/')) {
    return res.status(400).send('Only images allowed');
  }
  
  // Validate file size (additional check)
  if (file.size > 5 * 1024 * 1024) {
    return res.status(400).send('File too large');
  }
  
  // Process file
  const filename = Date.now() + '_' + file.name;
  file.mv('./uploads/' + filename, (err) => {
    if (err) return res.status(500).send(err);
    res.json({ message: 'Success', filename: filename });
  });
});

Safe File Naming

app.use(fileUpload({
  safeFileNames: true,      // Remove dangerous characters
  preserveExtension: 4,     // Keep up to 4-char extensions
  uriDecodeFileNames: true  // Decode URI-encoded names
}));

docs

index.md

tile.json