nestjs-fastify-upload
v1.0.0
Published
A high-performance, secure, and minimal fastify-multipart upload plugin for NestJS
Maintainers
Readme
nestjs-fastify-upload
A high-performance, secure, and minimal fastify-multipart upload plugin for NestJS. Engineered for scale and high concurrency, completely avoiding in-memory stream buffering unless necessary.
Supports ALL file types (Images, Videos, PDFs, CSVs, Binaries, etc.). You can easily process multiple files concurrently using the @UploadFiles() decorator while streaming them straight to disk.
🚀 Features
- Extreme Performance: Low latency, streams directly to disk avoiding RAM allocations efficiently handling massive concurrent uploads.
- Secure by Default: Validates dimensions, MIME types, and file extensions strictly.
- Minimal Dependencies: Relies solely on native promises and streams, with optional image processing using
jimp. - Easy NestJS Integration: Custom intuitive decorators for handling
@UploadFile()and@UploadFiles().
📦 Installation
npm install nestjs-fastify-upload jimp🛠️ Usage
Setup main.ts
Ensure your NestJS app uses Fastify and registers the internal FastifyUpload config:
import { NestFactory } from '@nestjs/core';
import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify';
import multipart from '@fastify/multipart';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter()
);
// Register the multipart plugin natively to allow fast streaming of our API uploads
await app.register(multipart);
await app.listen(3000);
}
bootstrap();Controller Integration
Import the decorators and UploadOptions directly in your controller:
import { Controller, Post, UseInterceptors } from '@nestjs/common';
import { FileInterceptor, FilesInterceptor, UploadFile, UploadFiles, UploadedFileResult } from 'nestjs-fastify-upload';
@Controller('upload')
export class UploadController {
@Post('profile-picture')
@UseInterceptors(FileInterceptor('file', {
dest: './storage/images',
allowedMimeTypes: ['image/jpeg', 'image/png', 'image/webp'],
resizeImage: { w: 400, h: 400 }, // Generates and resizes the image automatically!
maxFileSize: 5 * 1024 * 1024, // 5MB Limit Max
}))
uploadProfilePicture(@UploadFile() file: UploadedFileResult) {
return {
message: 'File successfully uploaded and resized',
file,
};
}
@Post('gallery')
@UseInterceptors(FilesInterceptor('files', {
dest: './storage/gallery',
maxFiles: 5,
maxFileSize: 10 * 1024 * 1024, // 10MB limit per individual file
}))
uploadGallery(@UploadFiles() files: UploadedFileResult[]) {
return {
message: 'Gallery files streamed successfully to disk!',
files,
};
}
}🛡️ Architecture & Security
- Asynchronous Disk Piping: Unlike traditional
Buffer.concat()routines which bloat Node's memory constraints during high-traffic video/image uploads,nestjs-fast-uploadopens direct Node Stream pipelines pushing multipart TCP packets gracefully directly to the NVMe/SSD. Memory allocations remain< 20MBeven during 1GB file transfers! - Auto-Cleanup: In cases of aborted user connections, excessive constraints (
PayloadTooLargeException), or validation failures, the residual partial files on disk are instantly safely unlinked to prevent capacity drains.
Options Config
| Option | Type | Description |
|--------|------|-------------|
| dest | String | (Required) Target directory where the file will be saved. Directory is created automatically if it doesn't exist. |
| maxFileSize | Number | Maximum size per file (in bytes). Default is 5MB. |
| allowedExtensions | String[] | Optional array of valid extensions e.g. ['.jpg', '.pdf']. |
| allowedMimeTypes | String[] | Optional array of valid MimeTypes e.g. ['image/png']. |
| resizeImage | { w: number, h: number } | Option specifically for images. When enabled, resizes the cover of the image precisely keeping Aspect Ratio with jimp. |
| maxFiles | Number | The maximal threshold of files allowed to be evaluated when using UploadFiles(). Default is 10. |
👨💻 Author
@royaltics.solutions
