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 theFastifyAdapter
.
For better type safety, let’s install Multer typings package:
$ 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.
@@filename()
@Post('upload')
@UseInterceptors(FileInterceptor('file'))
uploadFile(@UploadedFile() file: Express.Multer.File) {
console.log(file);
}
@@switch
@Post('upload')
@UseInterceptors(FileInterceptor('file'))
@Bind(UploadedFile())
uploadFile(file) {
console.log(file);
}
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 fileoptions
: optional object of typeMulterOptions
. 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 abovemaxCount
: optional number defining the maximum number of files to acceptoptions
: optionalMulterOptions
object, as described above
When using FilesInterceptor()
, extract files from the request
with the @UploadedFiles()
decorator.
@@filename()
@Post('upload')
@UseInterceptors(FilesInterceptor('files'))
uploadFile(@UploadedFiles() files: Array<Express.Multer.File>) {
console.log(files);
}
@@switch
@Post('upload')
@UseInterceptors(FilesInterceptor('files'))
@Bind(UploadedFiles())
uploadFile(files) {
console.log(files);
}
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 requiredname
property with a string value specifying a field name, as described above, and an optionalmaxCount
property, as described aboveoptions
: optionalMulterOptions
object, as described above
When using FileFieldsInterceptor()
, extract files from the request
with the @UploadedFiles()
decorator.
@@filename()
@Post('upload')
@UseInterceptors(FileFieldsInterceptor([
{ name: 'avatar', maxCount: 1 },
{ name: 'background', maxCount: 1 },
]))
uploadFile(@UploadedFiles() files: Express.Multer.File[]) {
console.log(files);
}
@@switch
@Post('upload')
@Bind(UploadedFiles())
@UseInterceptors(FileFieldsInterceptor([
{ name: 'avatar', maxCount: 1 },
{ name: 'background', maxCount: 1 },
]))
uploadFile(files) {
console.log(files);
}
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.
@@filename()
@Post('upload')
@UseInterceptors(AnyFilesInterceptor())
uploadFile(@UploadedFiles() files: Array<Express.Multer.File>) {
console.log(files);
}
@@switch
@Post('upload')
@Bind(UploadedFiles())
@UseInterceptors(AnyFilesInterceptor())
uploadFile(files) {
console.log(files);
}
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.
MulterModule.register({
dest: './upload',
});
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:
MulterModule.registerAsync({
useFactory: () => ({
dest: './upload',
}),
});
Like other factory providers, our factory function can be async
and can inject dependencies through inject
.
MulterModule.registerAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
dest: configService.getString('MULTER_DEST'),
}),
inject: [ConfigService],
});
Alternatively, you can configure the MulterModule
using a class instead of a factory, as shown below:
MulterModule.registerAsync({
useClass: MulterConfigService,
});
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.
@Injectable()
class MulterConfigService implements MulterOptionsFactory {
createMulterOptions(): MulterModuleOptions {
return {
dest: './upload',
};
}
}
If you want to reuse an existing options provider instead of creating a private copy inside the MulterModule
, use the useExisting
syntax.
MulterModule.registerAsync({
imports: [ConfigModule],
useExisting: ConfigService,
});
Example
A working example is available here.