File Uploads & Media Processing

15 questions found

How would you implement a progress indicator for a large file upload from the client's perspective, given the Node.js server side?

Intermediate
Upload progress tracking primarily happens client-side (using the browser's XMLHttpRequest upload.onprogress event or fetch with a ReadableStream), since the browser has direct visibility into how much of the request body has actually been sent -- server-side, you can additionally track how many bytes have been received so far (useful for logging or a websocket-pushed progress update to other connected clients), typically by listening to data events on the raw incoming request stream before it's fully parsed by multer.
// Client-side (the primary mechanism for progress)
const xhr = new XMLHttpRequest();
xhr.upload.onprogress = (event) => {
  const percent = (event.loaded / event.total) * 100;
  updateProgressBar(percent);
};
xhr.open('POST', '/upload');
xhr.send(formData);
Real-world example A file-upload UI shows a real-time progress bar using the browser's XMLHttpRequest upload progress event, giving users clear feedback during a large file transfer, entirely independent of anything the Node.js server needs to do differently to support it.

Common follow-ups: Why doesn't the more modern fetch() API have a built-in equivalent to XMLHttpRequest's upload.onprogress out of the box?;How would you push server-side processing progress (like 'transcoding: 40% complete') back to the client after the upload itself has finished?

HTTP & Web Servers;WebSockets & Real-Time Communication

How would you scan uploaded files for malware before accepting them into permanent storage in a Node.js application?

Advanced
A common approach integrates with a virus-scanning engine like ClamAV, running either as a local daemon the Node.js process communicates with over a socket (via a library like clamscan), or as a separate managed cloud service -- the uploaded file is scanned before being moved from a temporary quarantine location to permanent storage, and rejected (with the temporary file deleted) if the scan detects a threat, adding a crucial security layer for any application accepting file uploads from untrusted users.
const NodeClam = require('clamscan');
const clamscan = await new NodeClam().init({ clamdscan: { socket: '/var/run/clamav/clamd.ctl' } });

const { isInfected, viruses } = await clamscan.isInfected(req.file.path);
if (isInfected) {
  await fs.promises.unlink(req.file.path);
  return res.status(400).json({ error: 'File failed security scan', viruses });
}
Real-world example A document-sharing platform scans every uploaded file with ClamAV before moving it from a temporary quarantine folder to permanent cloud storage, ensuring a user can never inadvertently (or maliciously) distribute malware to other users through the platform's file-sharing feature.

Common follow-ups: How significant is the latency added by a virus scan to the overall upload flow, and how would you communicate that delay to the user?;What's the tradeoff of running this scan synchronously during the upload versus asynchronously after accepting the file into a quarantined state?

Security;Background Jobs & Queues

What is the difference between upload.single(), upload.array(), and upload.fields() in multer?

Intermediate
upload.single(fieldName) handles exactly one uploaded file under a specific form field name, populating req.file. upload.array(fieldName, maxCount) handles multiple files uploaded under the same field name (like several photos), populating req.files as an array. upload.fields([{ name, maxCount }, ...]) handles multiple distinct named fields, each potentially with its own file(s), useful when a form has several different types of file inputs (like a resume and a cover letter uploaded together).
app.post('/single', upload.single('avatar'), handler); // req.file
app.post('/multiple', upload.array('photos', 10), handler); // req.files (array)
app.post('/mixed', upload.fields([
  { name: 'resume', maxCount: 1 },
  { name: 'coverLetter', maxCount: 1 },
]), handler); // req.files.resume, req.files.coverLetter
Real-world example A job-application form uses upload.fields() to accept both a resume and a cover letter as two distinctly named file inputs in a single form submission, letting the handler access each one separately via req.files.resume and req.files.coverLetter.

Common follow-ups: What happens if a client attempts to upload more files than the maxCount limit specified for upload.array()?;How would you handle a form with a mix of both regular text fields and file uploads together?

Express & Middleware;HTTP & Web Servers

How would you implement resumable/chunked file uploads in Node.js to handle very large files over unreliable network connections?

Advanced
Chunked (resumable) uploads split a large file into smaller pieces on the client side, uploading each chunk as a separate request with metadata identifying its position within the overall file -- the server stores each received chunk (or appends it directly to a partially-assembled file) and, once all chunks have arrived, reassembles them into the complete file; if the connection drops mid-upload, only the remaining unsent chunks need to be retried, rather than restarting the entire upload from scratch.
app.post('/upload-chunk', upload.single('chunk'), async (req, res) => {
  const { uploadId, chunkIndex, totalChunks } = req.body;
  await fs.promises.rename(req.file.path, `./chunks/${uploadId}-${chunkIndex}`);

  const receivedChunks = await fs.promises.readdir('./chunks');
  if (receivedChunks.filter(f => f.startsWith(uploadId)).length === Number(totalChunks)) {
    await assembleChunksIntoFinalFile(uploadId, totalChunks);
  }
  res.json({ received: chunkIndex });
});
Real-world example A cloud-storage application supporting multi-gigabyte file uploads over potentially unstable mobile network connections implements chunked uploads, letting a user's upload resume from where it left off after a dropped connection rather than needing to restart the entire multi-gigabyte transfer.

Common follow-ups: How does a library like tus (an open protocol for resumable uploads) standardize this pattern rather than each application implementing it from scratch?;How do you handle cleaning up abandoned partial chunk uploads that are never completed?

Streams & Buffers;Error Handling

Why should an application typically avoid storing uploaded files directly on the same server instance that runs the web application?

Beginner
Storing uploaded files on local disk ties that data to a specific server instance, which breaks horizontal scaling (a file uploaded to one instance wouldn't be visible from requests handled by a different instance) and risks permanent data loss if that specific instance is terminated (common in cloud environments with ephemeral, disposable instances) -- the standard solution is storing uploaded files in a dedicated object storage service like Amazon S3, which is durable, accessible from any application instance, and decoupled entirely from the application server's own lifecycle.
// Fragile: tied to this specific server's local disk
await fs.promises.writeFile(`./uploads/${filename}`, fileBuffer);

// Durable and scalable: stored in shared cloud object storage
await s3Client.send(new PutObjectCommand({ Bucket: 'uploads', Key: filename, Body: fileBuffer }));
Real-world example A photo-sharing app that originally stored uploads on local disk lost user photos whenever a server instance was replaced during a routine deployment, until migrating to S3-based storage, after which uploaded files persisted reliably regardless of which server instance handled the original upload or any later requests for it.

Common follow-ups: How does this relate to the twelve-factor app principle of keeping application instances stateless, discussed earlier in Cloud & DevOps?;What's an appropriate migration strategy for moving from local-disk storage to S3 for an application already in production with existing uploaded files?

Cloud & DevOps;Architecture & Design Patterns

Showing 11–15 of 15