multipart/form-data parser which supports streaming
npx @tessl/cli install tessl/npm-multiparty@4.2.0multiparty is a Node.js library for parsing HTTP requests with content-type multipart/form-data, specifically designed for handling file uploads with streaming support. It provides a comprehensive API for processing form data without loading entire files into memory, making it ideal for efficient file upload handling in web applications.
npm install multipartyconst multiparty = require('multiparty');For ES modules:
import * as multiparty from 'multiparty';const multiparty = require('multiparty');
const http = require('http');
http.createServer(function(req, res) {
if (req.url === '/upload' && req.method === 'POST') {
// Parse a file upload with callback
const form = new multiparty.Form();
form.parse(req, function(err, fields, files) {
if (err) {
res.writeHead(400, { 'content-type': 'text/plain' });
res.end('Error: ' + err.message);
return;
}
res.writeHead(200, { 'content-type': 'application/json' });
res.end(JSON.stringify({ fields, files }));
});
}
}).listen(8080);multiparty is built around several key concepts:
Creates a new multipart form parser with optional configuration.
/**
* Creates a new multipart form parser
* @param {Object} options - Configuration options
*/
function Form(options);
interface FormOptions {
/** Encoding for incoming form fields (default: 'utf8') */
encoding?: string;
/** Maximum memory for all fields in bytes (default: 2MB) */
maxFieldsSize?: number;
/** Maximum number of fields to parse (default: 1000) */
maxFields?: number;
/** Maximum total bytes for all files (default: Infinity) */
maxFilesSize?: number;
/** Enable automatic field event emission (default: false) */
autoFields?: boolean;
/** Enable automatic file event emission (default: false) */
autoFiles?: boolean;
/** Directory for temporary file uploads (default: os.tmpdir()) */
uploadDir?: string;
}Parses an incoming HTTP request containing multipart form data.
/**
* Parse an HTTP request with multipart form data
* @param {IncomingMessage} request - Node.js HTTP request object
* @param {Function} [callback] - Optional callback for simplified usage
*/
form.parse(request, callback);
/**
* Callback function signature when provided
* @param {Error|null} err - Error if parsing failed
* @param {Object} fields - Object with field names as keys, arrays of values as values
* @param {Object} files - Object with field names as keys, arrays of file objects as values
*/
function parseCallback(err, fields, files);Access current parsing state and progress information.
/** Current number of bytes received */
form.bytesReceived: number;
/** Expected total bytes from Content-Length header */
form.bytesExpected: number | null;
/** Current error state of the parser */
form.error: Error | null;
/** Array of currently opened file handles */
form.openedFiles: Array;
/** Total size of all parsed field data */
form.totalFieldSize: number;
/** Total count of parsed fields */
form.totalFieldCount: number;
/** Total size of all parsed file data */
form.totalFileSize: number;multiparty uses an event-driven architecture for handling different stages of form parsing.
/**
* Error event - emitted when parsing encounters an error
* @param {Error} err - Error object with optional statusCode property
*/
form.on('error', function(err));
/**
* Part event - emitted for each part in the multipart data
* @param {ReadableStream} part - Stream for the part data
*/
form.on('part', function(part));
/**
* Field event - emitted for each form field (requires autoFields)
* @param {string} name - Field name
* @param {string} value - Field value
*/
form.on('field', function(name, value));
/**
* File event - emitted for each file upload (requires autoFiles)
* @param {string} name - Field name for the file
* @param {Object} file - File object with metadata
*/
form.on('file', function(name, file));
/**
* Progress event - emitted during parsing for progress tracking
* @param {number} bytesReceived - Total bytes received so far
* @param {number|null} bytesExpected - Expected total bytes
*/
form.on('progress', function(bytesReceived, bytesExpected));
/**
* Close event - emitted when parsing completes successfully
*/
form.on('close', function());
/**
* Aborted event - emitted when request is aborted
*/
form.on('aborted', function());When handling part events, the part stream has additional properties for metadata.
interface PartStream extends ReadableStream {
/** HTTP headers for this part */
headers: Object;
/** Field name for this part */
name: string;
/** Filename if this part is a file upload */
filename?: string;
/** Byte offset of this part in the request body */
byteOffset: number;
/** Size of this part in bytes (if known) */
byteCount?: number;
}When using autoFiles mode or the parse callback, files are represented as objects with metadata.
interface FileObject {
/** Field name for this file */
fieldName: string;
/** Original filename as reported by the client */
originalFilename: string;
/** Absolute path where the file was saved on disk */
path: string;
/** HTTP headers sent with this file */
headers: Object;
/** Size of the uploaded file in bytes */
size: number;
}const form = new multiparty.Form({
uploadDir: './uploads',
maxFilesSize: 50 * 1024 * 1024 // 50MB limit
});
form.on('error', function(err) {
console.error('Parsing error:', err.message);
if (err.statusCode) {
res.writeHead(err.statusCode);
}
res.end('Upload failed: ' + err.message);
});
form.on('part', function(part) {
console.log('Received part:', part.name);
if (part.filename) {
console.log('File upload:', part.filename);
// Handle file part
part.on('data', function(chunk) {
// Process file chunk
});
} else {
console.log('Form field:', part.name);
// Handle field part
part.resume(); // Skip field data
}
});
form.on('close', function() {
console.log('Upload completed successfully');
res.writeHead(200);
res.end('Upload complete');
});
form.parse(req);const form = new multiparty.Form({
uploadDir: './uploads',
maxFilesSize: 100 * 1024 * 1024, // 100MB total
maxFieldsSize: 2 * 1024 * 1024 // 2MB for fields
});
form.on('file', function(name, file) {
console.log('File uploaded:', {
field: name,
filename: file.originalFilename,
path: file.path,
size: file.size
});
// File is automatically saved to disk at file.path
// You can now move it to a permanent location
});
form.on('field', function(name, value) {
console.log('Field received:', name, '=', value);
});
form.parse(req);const form = new multiparty.Form();
form.on('progress', function(bytesReceived, bytesExpected) {
if (bytesExpected) {
const percent = Math.round((bytesReceived / bytesExpected) * 100);
console.log(`Upload progress: ${percent}% (${bytesReceived} / ${bytesExpected} bytes)`);
} else {
console.log(`Upload progress: ${bytesReceived} bytes received`);
}
});
form.parse(req);multiparty provides detailed error handling with HTTP status codes for common scenarios:
form.on('error', function(err) {
console.error('Parse error:', err.message);
// Check for specific error conditions
if (err.statusCode === 413) {
console.log('Upload too large');
} else if (err.statusCode === 400) {
console.log('Malformed request');
}
// Send appropriate HTTP response
res.writeHead(err.statusCode || 500);
res.end(err.message);
});const form = new multiparty.Form({
encoding: 'utf8',
maxFieldsSize: 2 * 1024 * 1024, // 2MB for form fields
maxFields: 100, // Limit number of fields
maxFilesSize: 50 * 1024 * 1024, // 50MB total for files
uploadDir: '/tmp/uploads' // Dedicated upload directory
});const form = new multiparty.Form({
encoding: 'utf8',
maxFieldsSize: 10 * 1024 * 1024, // 10MB for testing
maxFields: 1000, // Default
maxFilesSize: 100 * 1024 * 1024, // 100MB for testing
uploadDir: './dev-uploads' // Local development directory
});