File upload

To handle file uploading, Nest provides a built-in module based on the multer middleware package for Express. Multer handles data posted in the multipart/form-data format, which is primarily used for uploading files via an HTTP POST request. This module is fully configurable and you can adjust its behavior to your application requirements.

warning Warning Multer cannot process data which is not in the supported multipart format (multipart/form-data). Also, note that this package is not compatible with the FastifyAdapter.

For better type safety, let’s install Multer typings package:

  1. $ npm i -D @types/multer

With this package installed, we can now use the Express.Multer.File type (you can import this type as follows: import {{ '{' }} Express {{ '}' }} from 'express').

Basic example

To upload a single file, simply tie the FileInterceptor() interceptor to the route handler and extract file from the request using the @UploadedFile() decorator.

  1. @@filename()
  2. @Post('upload')
  3. @UseInterceptors(FileInterceptor('file'))
  4. uploadFile(@UploadedFile() file: Express.Multer.File) {
  5. console.log(file);
  6. }
  7. @@switch
  8. @Post('upload')
  9. @UseInterceptors(FileInterceptor('file'))
  10. @Bind(UploadedFile())
  11. uploadFile(file) {
  12. console.log(file);
  13. }

info Hint The FileInterceptor() decorator is exported from the @nestjs/platform-express package. The @UploadedFile() decorator is exported from @nestjs/common.

The FileInterceptor() decorator takes two arguments:

  • fieldName: string that supplies the name of the field from the HTML form that holds a file
  • options: optional object of type MulterOptions. This is the same object used by the multer constructor (more details here).

warning Warning FileInterceptor() may not be compatible with third party cloud providers like Google Firebase or others.

Array of files

To upload an array of files (identified with a single field name), use the FilesInterceptor() decorator (note the plural Files in the decorator name). This decorator takes three arguments:

  • fieldName: as described above
  • maxCount: optional number defining the maximum number of files to accept
  • options: optional MulterOptions object, as described above

When using FilesInterceptor(), extract files from the request with the @UploadedFiles() decorator.

  1. @@filename()
  2. @Post('upload')
  3. @UseInterceptors(FilesInterceptor('files'))
  4. uploadFile(@UploadedFiles() files: Array<Express.Multer.File>) {
  5. console.log(files);
  6. }
  7. @@switch
  8. @Post('upload')
  9. @UseInterceptors(FilesInterceptor('files'))
  10. @Bind(UploadedFiles())
  11. uploadFile(files) {
  12. console.log(files);
  13. }

info Hint The FilesInterceptor() decorator is exported from the @nestjs/platform-express package. The @UploadedFiles() decorator is exported from @nestjs/common.

Multiple files

To upload multiple fields (all with different field name keys), use the FileFieldsInterceptor() decorator. This decorator takes two arguments:

  • uploadedFields: an array of objects, where each object specifies a required name property with a string value specifying a field name, as described above, and an optional maxCount property, as described above
  • options: optional MulterOptions object, as described above

When using FileFieldsInterceptor(), extract files from the request with the @UploadedFiles() decorator.

  1. @@filename()
  2. @Post('upload')
  3. @UseInterceptors(FileFieldsInterceptor([
  4. { name: 'avatar', maxCount: 1 },
  5. { name: 'background', maxCount: 1 },
  6. ]))
  7. uploadFile(@UploadedFiles() files: Express.Multer.File[]) {
  8. console.log(files);
  9. }
  10. @@switch
  11. @Post('upload')
  12. @Bind(UploadedFiles())
  13. @UseInterceptors(FileFieldsInterceptor([
  14. { name: 'avatar', maxCount: 1 },
  15. { name: 'background', maxCount: 1 },
  16. ]))
  17. uploadFile(files) {
  18. console.log(files);
  19. }

Any files

To upload all fields with arbitrary field name keys, use the AnyFilesInterceptor() decorator. This decorator can accept an optional options object as described above.

When using AnyFilesInterceptor(), extract files from the request with the @UploadedFiles() decorator.

  1. @@filename()
  2. @Post('upload')
  3. @UseInterceptors(AnyFilesInterceptor())
  4. uploadFile(@UploadedFiles() files: Array<Express.Multer.File>) {
  5. console.log(files);
  6. }
  7. @@switch
  8. @Post('upload')
  9. @Bind(UploadedFiles())
  10. @UseInterceptors(AnyFilesInterceptor())
  11. uploadFile(files) {
  12. console.log(files);
  13. }

Default options

You can specify multer options in the file interceptors as described above. To set default options, you can call the static register() method when you import the MulterModule, passing in supported options. You can use all options listed here.

  1. MulterModule.register({
  2. dest: './upload',
  3. });

info Hint The MulterModule class is exported from the @nestjs/platform-express package.

Async configuration

When you need to set MulterModule options asynchronously instead of statically, use the registerAsync() method. As with most dynamic modules, Nest provides several techniques to deal with async configuration.

One technique is to use a factory function:

  1. MulterModule.registerAsync({
  2. useFactory: () => ({
  3. dest: './upload',
  4. }),
  5. });

Like other factory providers, our factory function can be async and can inject dependencies through inject.

  1. MulterModule.registerAsync({
  2. imports: [ConfigModule],
  3. useFactory: async (configService: ConfigService) => ({
  4. dest: configService.getString('MULTER_DEST'),
  5. }),
  6. inject: [ConfigService],
  7. });

Alternatively, you can configure the MulterModule using a class instead of a factory, as shown below:

  1. MulterModule.registerAsync({
  2. useClass: MulterConfigService,
  3. });

The construction above instantiates MulterConfigService inside MulterModule, using it to create the required options object. Note that in this example, the MulterConfigService has to implement the MulterOptionsFactory interface, as shown below. The MulterModule will call the createMulterOptions() method on the instantiated object of the supplied class.

  1. @Injectable()
  2. class MulterConfigService implements MulterOptionsFactory {
  3. createMulterOptions(): MulterModuleOptions {
  4. return {
  5. dest: './upload',
  6. };
  7. }
  8. }

If you want to reuse an existing options provider instead of creating a private copy inside the MulterModule, use the useExisting syntax.

  1. MulterModule.registerAsync({
  2. imports: [ConfigModule],
  3. useExisting: ConfigService,
  4. });

Example

A working example is available here.