Express.js
Handle MultipleUpload file uploads with Express and the
multer middleware for multipart parsing.
This guide covers both standard uploads and chunked uploads with resume support.
Multipart Form Upload
Use multer to handle multipart/form-data. Files are saved to disk with a unique GUID filename.
const express = require("express");
const multer = require("multer");
const path = require("path");
const crypto = require("crypto");
const fs = require("fs");
const cors = require("cors");
const app = express();
const UPLOAD_DIR = path.join(__dirname, "uploads");
if (!fs.existsSync(UPLOAD_DIR)) fs.mkdirSync(UPLOAD_DIR, { recursive: true });
app.use(cors({
allowedHeaders: [
"Content-Type", "X-Upload-Id", "X-Chunk-Index",
"X-Chunk-Count", "X-File-Name", "X-File-Size"
]
}));
const storage = multer.diskStorage({
destination: UPLOAD_DIR,
filename: (req, file, cb) => {
const guid = crypto.randomUUID();
const ext = path.extname(file.originalname);
req.fileGuid = guid;
cb(null, guid + ext);
}
});
const upload = multer({
storage,
limits: { fileSize: 200 * 1024 * 1024 } // 200 MB
});
app.post("/upload", upload.single("file"), (req, res) => {
res.json({
success: true,
fileGuid: req.fileGuid,
fileName: req.file.originalname,
fileSize: req.file.size
});
}); Chunked Upload
For large files, MultipleUpload sends raw body chunks with custom headers. Store each chunk and assemble the final file once all chunks arrive.
const CHUNK_DIR = path.join(UPLOAD_DIR, "chunks");
app.post("/upload-chunk", express.raw({ type: "*/*", limit: "50mb" }), (req, res) => {
const uploadId = req.headers["x-upload-id"];
const chunkIndex = parseInt(req.headers["x-chunk-index"], 10);
const chunkCount = parseInt(req.headers["x-chunk-count"], 10);
const fileName = req.headers["x-file-name"];
const fileSize = parseInt(req.headers["x-file-size"], 10);
const sessionDir = path.join(CHUNK_DIR, uploadId);
if (!fs.existsSync(sessionDir)) fs.mkdirSync(sessionDir, { recursive: true });
// Save this chunk
fs.writeFileSync(path.join(sessionDir, `chunk_${chunkIndex}`), req.body);
const received = fs.readdirSync(sessionDir).length;
if (received === chunkCount) {
// Assemble final file
const fileGuid = crypto.randomUUID();
const ext = path.extname(fileName);
const finalPath = path.join(UPLOAD_DIR, fileGuid + ext);
const output = fs.createWriteStream(finalPath);
for (let i = 0; i < chunkCount; i++) {
const chunkData = fs.readFileSync(path.join(sessionDir, `chunk_${i}`));
output.write(chunkData);
}
output.end();
// Clean up chunks
fs.rmSync(sessionDir, { recursive: true });
return res.json({
success: true,
fileGuid: fileGuid,
fileName: fileName,
fileSize: fileSize
});
}
res.json({ success: true, chunksReceived: received });
});
app.listen(3000, () => console.log("Express upload server on http://localhost:3000")); Expected JSON Response
Both endpoints must return this JSON structure on successful upload completion.
{
"success": true,
"fileGuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"fileName": "photo.jpg",
"fileSize": 204800
} Client-Side JavaScript
Initialize MultipleUpload on the client, pointing to your Express endpoints.
<link rel="stylesheet" href="multipleupload.css" />
<div id="uploader"></div>
<script src="multipleupload.js"></script>
<script>
var uploader = new MultipleUpload("#uploader", {
uploadUrl: "http://localhost:3000/upload",
chunkUploadUrl: "http://localhost:3000/upload-chunk",
chunkSize: 2 * 1024 * 1024, // 2 MB chunks
onFileUploaded: function (file, response) {
console.log("Uploaded:", response.fileName, response.fileGuid);
}
});
</script>