js

Build High-Performance File Upload Service: Fastify, Multipart Streams, and S3 Integration Guide

Learn to build a scalable file upload service using Fastify multipart streams and direct S3 integration. Complete guide with TypeScript, validation, and production best practices.

Build High-Performance File Upload Service: Fastify, Multipart Streams, and S3 Integration Guide

I’ve been thinking a lot about file uploads lately. Every modern application needs them, yet many implementations struggle with performance, scalability, and security. What if we could build an upload service that handles large files efficiently without crashing servers? That’s exactly what we’ll create today using Fastify, multipart streams, and AWS S3. Stick with me - you’ll learn how to build a production-ready solution that scales.

First, let’s set up our project. Create a new directory and initialize it with npm. We’ll need several key dependencies:

npm install fastify @fastify/multipart @aws-sdk/client-s3
npm install dotenv joi mime-types

These packages give us our web framework, file handling capabilities, AWS integration, and validation tools. Notice we’re installing specific AWS SDK v3 packages - they’re more modular and efficient than the old monolithic SDK.

Now for TypeScript configuration. Create a tsconfig.json with strict type checking enabled. This catches errors early and improves code quality. Why risk runtime errors when TypeScript can prevent them during development?

Configuring Fastify requires special attention to multipart handling. We want streaming capabilities, not buffering entire files in memory. Here’s how I set it up:

await server.register(multipart, {
  limits: {
    fileSize: config.MAX_FILE_SIZE,
    files: config.MAX_FILES_PER_REQUEST
  },
  attachFieldsToBody: false
});

By setting attachFieldsToBody: false, we take manual control of file streams. This prevents Fastify from buffering files and allows direct piping to S3. How much memory could we save by avoiding buffering? For 100 concurrent 1GB uploads, we’d avoid 100GB of memory usage!

For AWS integration, we need robust S3 configuration. The @aws-sdk/lib-storage package provides the Upload class that handles multipart uploads automatically:

const upload = new Upload({
  client: s3Client,
  params: {
    Bucket: 'my-bucket',
    Key: filename,
    Body: fileStream
  },
  partSize: 5 * 1024 * 1024
});

await upload.done();

This code streams files directly to S3 in 5MB chunks. If the connection drops, it can resume automatically. What would happen if we didn’t use multipart uploads? Large files would fail completely on network issues.

Validation is crucial for security. We check file types and sizes before processing:

const allowedTypes = ['image/jpeg', 'image/png'];
if (!allowedTypes.includes(mimetype)) {
  throw new Error('Invalid file type');
}

For images, I often add Sharp.js for resizing during upload. It processes images as streams without saving intermediates. Could we prevent storage attacks by validating before any processing? Absolutely - we reject invalid files immediately.

Users love progress indicators. We implement server-sent events for real-time updates:

res.write(`data: ${JSON.stringify(progress)}\n\n`);

This sends progress percentages to the client. How responsive would your UI feel with live progress bars?

Error handling must be comprehensive. We wrap uploads in try-catch blocks and implement retry logic:

try {
  await uploadStream();
} catch (err) {
  if (err instanceof TimeoutError) {
    await retryUpload();
  }
}

For production, we add rate limiting with @fastify/rate-limit. It prevents abuse by limiting requests per IP. What could happen without rate limiting? One malicious user could overload your system.

Testing is straightforward with tools like Postman. I simulate slow connections to verify progress tracking. Always test failure scenarios - what happens when S3 credentials expire? Our error handler returns clear messages without exposing internals.

In production, consider these additions:

  • Use AWS Instance Roles instead of access keys
  • Enable S3 server access logging
  • Set lifecycle policies to transition files to Glacier
  • Implement CloudFront for faster downloads

We’ve built a high-performance upload service that streams files directly to S3. It handles large files efficiently, validates securely, and provides user feedback. This approach saves server resources while maintaining reliability. What file handling challenges could this solve for your projects?

If you found this useful, share it with your network. Have questions or improvements? Let me know in the comments - I read every response and appreciate your insights.

Keywords: fastify file upload, multipart streams nodejs, S3 file upload service, AWS S3 streaming upload, TypeScript file upload API, high performance file upload, Fastify multipart handling, Node.js S3 integration, file upload validation security, streaming file upload tutorial



Similar Posts
Blog Image
Build Complete NestJS Authentication System with Refresh Tokens, Prisma, and Redis

Learn to build a complete authentication system with JWT refresh tokens using NestJS, Prisma, and Redis. Includes secure session management, token rotation, and guards.

Blog Image
Build Production-Ready Event-Driven Architecture: Node.js, Redis Streams, TypeScript Guide

Learn to build scalable event-driven systems with Node.js, Redis Streams & TypeScript. Master event sourcing, error handling, and production deployment.

Blog Image
Event Sourcing with Node.js, TypeScript & PostgreSQL: Complete Implementation Guide 2024

Master Event Sourcing with Node.js, TypeScript & PostgreSQL. Learn to build event stores, handle aggregates, implement projections, and manage concurrency. Complete tutorial with practical examples.

Blog Image
Build Production-Ready GraphQL APIs with Apollo Server, TypeScript, and Prisma: Complete Guide

Learn to build production-ready GraphQL APIs with Apollo Server, TypeScript & Prisma. Complete guide with auth, performance optimization & deployment.

Blog Image
Complete Event-Driven Microservices Architecture with NestJS, RabbitMQ and MongoDB: 2024 Guide

Learn to build scalable event-driven microservices with NestJS, RabbitMQ & MongoDB. Master CQRS, Saga patterns, and deployment strategies.

Blog Image
Build High-Performance Rate Limiting Middleware with Redis and Node.js: Complete Tutorial

Learn to build scalable rate limiting middleware with Redis & Node.js. Master token bucket, sliding window algorithms for high-performance API protection.