Multipart Uploads

File Uploads and Multipart Data

A browser upload arrives as multipart/form-data: one body split by a boundary string into parts, each with its own headers. node:http has no parser for it, but undici 7,705 does — wrap the request in a Web Request and call formData().

Parsing an upload with the Web Request APIJavaScript
import { createServer } from 'node:http';
import { Readable } from 'node:stream';
createServer(async (req, res) => {
  const request = new Request('http://localhost/upload',
    { method: req.method, headers: req.headers, body: Readable.toWeb(req), duplex: 'half' });
  for (const [name, value] of await request.formData()) {
    if (typeof value === 'string') console.log(`field ${name} = ${value}`);
    else console.log(`file  ${name} = ${value.name} ${value.type} ${value.size} bytes`);
  }
  res.writeHead(201).end('stored\n');
}).listen(3003, '127.0.0.1');
Output
field title = Field notes
file  file = notes.txt text/plain 24 bytes

That is the log from curl 3,008 -F "title=Field notes" -F "file=@notes.txt" localhost:3003/upload. Text parts arrive as strings, file parts as File objects with name, type, size and stream(); duplex: 'half' is mandatory when a Request body is a stream. The catch: formData() buffers every part in memory — fine for an avatar, ruinous for a 2 GB video. For anything larger use busboy 2,997 (https://github.com/mscdex/busboy 2,997 ), a readable stream per part, or multer 12,087 (https://github.com/expressjs/multer 12,087 ) (2.4.0, MIT), the Express 24,430 middleware Express.js uses.