File Uploads in NestJS: Handling Files with Multer

@rnab
3 min readJan 7, 2025

--

NestJS is a modern Node.js framework for building efficient and scalable server-side applications. Built on TypeScript, it offers a robust architecture that enables developers to create modular, maintainable code. One common requirement for server-side applications is handling file uploads, which can be a tricky process. Fortunately, NestJS makes this easy with the Multer package.

In this article, you will learn how to handle file uploads in a NestJS application using Multer. We’ll cover everything from setting up your NestJS project to processing file uploads with Multer.

Getting Started

  1. Setting Up Your NestJS Project

First, we’ll create a new NestJS project. If you haven’t already installed the Nest CLI, you can do so with the following command:

npm install -g @nestjs/cli

Now, create a new project:

nest new file-upload-app
cd file-upload-app
  1. Install Multer

After setting up your project, you’ll need to install Multer, a middleware for handling multipart/form-data, which is primarily used for uploading files. NestJS provides an easy way to integrate Multer:

npm install @nestjs/platform-express multer

Configuring File Uploads

  1. Create a File Upload Endpoint

NestJS allows us to use decorators to handle HTTP requests efficiently. We’ll start by creating a new controller to handle file uploads.

Create a new module, controller, and service for file upload handling:

nest generate module upload
nest generate controller upload
nest generate service upload
  1. Using Multer in the Controller

Now, let’s set up the controller to handle file uploads. Open src/upload/upload.controller.ts and update it as follows:

import { Controller, Post, UploadedFile, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { UploadService } from './upload.service';

@Controller('upload')
export class UploadController {
constructor(private readonly uploadService: UploadService) {}

@Post('file')
@UseInterceptors(FileInterceptor('file'))
uploadFile(@UploadedFile() file: Express.Multer.File) {
return this.uploadService.saveFile(file);
}
}

Here, the @Post('file') decorator indicates that this route will handle POST requests to /upload/file. The @UseInterceptors(FileInterceptor('file')) decorator uses Multer’s FileInterceptor to process the uploaded file. The @UploadedFile() decorator allows us to access the uploaded file in the handler method.

  1. Processing the Uploaded File

Let’s handle file saving in the service. Open src/upload/upload.service.ts and update it:

import { Injectable } from '@nestjs/common';
import { writeFile } from 'fs/promises';

@Injectable()
export class UploadService {
async saveFile(file: Express.Multer.File): Promise<{message: string}> {
const uploadPath = `./uploads/${file.originalname}`;
await writeFile(uploadPath, file.buffer);
return { message: `File uploaded successfully! Path: ${uploadPath}` };
}
}

In this example, the service writes the uploaded file’s buffer to the filesystem. Make sure you’ve got an uploads directory in your project root, or you can create it:

mkdir uploads

Configuration Enhancements

  1. File Validation and Limits

You can also add additional constraints on file uploads such as file size limits, file type validation, etc. This can be done by configuring Multer options in a custom provider or directly in the controller.

In the controller, you can configure Multer options directly:

import { multerOptions } from './multer-options';
import { Controller, Post, UploadedFile, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { UploadService } from './upload.service';

@Controller('upload')
export class UploadController {
constructor(private readonly uploadService: UploadService) {}

@Post('file')
@UseInterceptors(FileInterceptor('file', multerOptions))
uploadFile(@UploadedFile() file: Express.Multer.File) {
return this.uploadService.saveFile(file);
}
}

Define multerOptions in a separate file, e.g., src/upload/multer-options.ts:

import { diskStorage } from 'multer';

export const multerOptions = {
storage: diskStorage({
destination: './uploads',
filename: (req, file, callback) => {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
const originalName = file.originalname.replace(/\s+/g, '-');
const filename = `${uniqueSuffix}-${originalName}`;
callback(null, filename);
},
}),
limits: {
fileSize: 1024 * 1024 * 5, // 5 MB
},
fileFilter: (req, file, callback) => {
if (!file.mimetype.match(/\/(jpg|jpeg|png|gif)$/)) {
req.fileValidationError = 'Only image files are allowed!';
return callback(null, false, new Error('Only image files are allowed!'));
}
callback(null, true);
},
};

Security Considerations

When handling file uploads, consider the following security tips:

  • Validate the file type and size.
  • Store the files in a secure location with appropriate access controls.
  • Sanitize filenames to prevent directory traversal attacks.

Conclusion

In this article, you’ve learned how to handle file uploads in a NestJS application using Multer. You set up a new NestJS project, configured Multer to handle file uploads, and learned how to process and save those files securely.

NestJS, combined with Multer, provides a simple yet powerful way to handle file uploads in your server-side applications. Happy coding!

Feel free to comment below with any questions or share your experiences with file uploads in NestJS.

--

--

@rnab
@rnab

Written by @rnab

Typescript, Devops, Kubernetes, AWS, AI/ML, Algo Trading

No responses yet