npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@mjackson/form-data-parser

v0.9.1

Published

A request.formData() wrapper with streaming file upload handling

Readme

form-data-parser

A streaming multipart/form-data parser that solves memory issues with file uploads in server environments. Built as an enhanced replacement for the native request.formData() API, it enables efficient handling of large file uploads by streaming directly to disk or cloud storage services like AWS S3 or Cloudflare R2, preventing server crashes from memory exhaustion.

Features

  • Drop-in replacement for request.formData() with streaming file upload support
  • Minimal buffering - processes file upload streams with minimal memory footprint
  • Standards-based - built on the web Streams API and File API
  • Smart fallback - automatically uses native request.formData() for non-multipart/form-data requests
  • Storage agnostic - works with any storage backend (local disk, S3, R2, etc.)

Why You Need This

The native request.formData() method has a few major flaws in server environments:

  • It buffers all file uploads in memory
  • It does not provide fine-grained control over file upload handling
  • It does not prevent DoS attacks from malicious requests

In normal usage, this makes it difficult to process requests with large file uploads because they can exhaust your server's RAM and crash the application.

For attackers, this creates an attack vector where malicious actors can overwhelm your server's memory by sending large payloads with many files.

form-data-parser solves this by handling file uploads as they arrive in the request body stream, allowing you to safely store files and use either a) the File directly or b) a unique identifier for that file in the returned FormData object.

Installation

Install from npm:

npm install @mjackson/form-data-parser

Usage

The parseFormData interface allows you to define an "upload handler" function for fine-grained control of handling file uploads.

import * as fsp from 'node:fs/promises';
import type { FileUpload } from '@mjackson/form-data-parser';
import { parseFormData } from '@mjackson/form-data-parser';

// Define how to handle incoming file uploads
async function uploadHandler(fileUpload: FileUpload) {
  // Is this file upload from the <input type="file" name="user-avatar"> field?
  if (fileUpload.fieldName === 'user-avatar') {
    let filename = `/uploads/user-${user.id}-avatar.bin`;

    // Store the file safely on disk
    await fsp.writeFile(filename, fileUpload.bytes);

    // Return the file name to use in the FormData object so we don't
    // keep the file contents around in memory.
    return filename;
  }

  // Ignore unrecognized fields
}

// Handle form submissions with file uploads
async function requestHandler(request: Request) {
  // Parse the form data from the request.body stream, passing any files
  // through your upload handler as they are parsed from the stream
  let formData = await parseFormData(request, uploadHandler);

  let avatarFilename = formData.get('user-avatar');

  if (avatarFilename != null) {
    console.log(`User avatar uploaded to ${avatarFilename}`);
  } else {
    console.log(`No user avatar file was uploaded`);
  }
}

To limit the maximum size of files that are uploaded, or the maximum number of files that may be uploaded in a single request, use the maxFileSize and maxFiles options.

import { MaxFilesExceededError, MaxFileSizeExceededError } from '@mjackson/form-data-parser';

const oneKb = 1024;
const oneMb = 1024 * oneKb;

try {
  let formData = await parseFormData(request, {
    maxFiles: 5,
    maxFileSize: 10 * oneMb,
  });
} catch (error) {
  if (error instanceof MaxFilesExceededError) {
    console.error(`Request may not contain more than 5 files`);
  } else if (error instanceof MaxFileSizeExceededError) {
    console.error(`Files may not be larger than 10 MiB`);
  } else {
    console.error(`An unknown error occurred:`, error);
  }
}

If you're looking for a more flexible storage solution for File objects that are uploaded, this library pairs really well with the file-storage library for keeping files in various storage backends.

import { LocalFileStorage } from '@mjackson/file-storage/local';
import type { FileUpload } from '@mjackson/form-data-parser';
import { parseFormData } from '@mjackson/form-data-parser';

// Set up storage for uploaded files
const fileStorage = new LocalFileStorage('/uploads/user-avatars');

// Define how to handle incoming file uploads
async function uploadHandler(fileUpload: FileUpload) {
  // Is this file upload from the <input type="file" name="user-avatar"> field?
  if (fileUpload.fieldName === 'user-avatar') {
    let storageKey = `user-${user.id}-avatar`;

    // Put the file in storage
    await fileStorage.set(storageKey, fileUpload);

    // Return a lazy File object that can access the stored file when needed
    return fileStorage.get(storageKey);
  }

  // Ignore unrecognized fields
}

Related Packages

  • file-storage - A simple key/value interface for storing FileUpload objects you get from the parser
  • multipart-parser - The parser used internally for parsing multipart/form-data HTTP messages

License

See LICENSE