File upload support for NestJS that works with both the Fastify and Express adapters, built directly on @fastify/busboy (the underlying multipart parser).
This package replaces @nest-lab/fastify-multer, which depends on the unmaintained fastify-multer library and does not support Fastify v5.
npm i nestjs-busboy
yarn add nestjs-busboy
pnpm i nestjs-busboyUse this exactly like you would the MulterModule from @nestjs/platform-express. The same interceptors, storage engines, and options are supported.
You must import BusboyModule somewhere in your application so that the multipart/form-data content-type parser is registered with Fastify (on Express this step is a no-op).
import { BusboyModule } from 'nestjs-busboy';
@Module({
imports: [BusboyModule],
})
export class AppModule {}import { BusboyModule, memoryStorage } from 'nestjs-busboy';
@Module({
imports: [
BusboyModule.register({
storage: memoryStorage(),
}),
],
})
export class AppModule {}@Module({
imports: [
BusboyModule.registerAsync({
useFactory: (config: ConfigService) => ({
dest: config.get('UPLOAD_DIR'),
}),
inject: [ConfigService],
}),
],
})
export class AppModule {}All interceptors accept an optional localOptions argument that is merged with module-level options.
import {
AnyFilesInterceptor,
FileFieldsInterceptor,
FileInterceptor,
FilesInterceptor,
NoFilesInterceptor,
memoryStorage,
} from 'nestjs-busboy';
@Controller('upload')
export class UploadController {
// Single file from field "file"
@Post('single')
@UseInterceptors(FileInterceptor('file', { storage: memoryStorage() }))
uploadSingle(@UploadedFile() file: Express.Multer.File) { ... }
// Up to 10 files from field "files"
@Post('multiple')
@UseInterceptors(FilesInterceptor('files', 10, { storage: memoryStorage() }))
uploadMultiple(@UploadedFiles() files: Express.Multer.File[]) { ... }
// Any files from any field
@Post('any')
@UseInterceptors(AnyFilesInterceptor({ storage: memoryStorage() }))
uploadAny(@UploadedFiles() files: Express.Multer.File[]) { ... }
// Named fields
@Post('fields')
@UseInterceptors(
FileFieldsInterceptor([{ name: 'avatar' }, { name: 'cover', maxCount: 1 }], {
storage: memoryStorage(),
}),
)
uploadFields(@UploadedFiles() files: { avatar?: Express.Multer.File[]; cover?: Express.Multer.File[] }) { ... }
// No files allowed — parses form fields only
@Post('form')
@UseInterceptors(NoFilesInterceptor())
formData(@Body() body: Record<string, string>) { ... }
}Files are buffered in memory as Buffer objects. This is the default when neither storage nor dest is specified.
import { memoryStorage } from 'nestjs-busboy';
FileInterceptor('file', { storage: memoryStorage() })Files are written to disk. The destination directory is created automatically.
import { diskStorage } from 'nestjs-busboy';
FileInterceptor('file', {
storage: diskStorage({
destination: '/uploads',
filename: (req, file, cb) => cb(null, `${Date.now()}-${file.originalname}`),
}),
})Or use the dest shorthand (generates random filenames):
BusboyModule.register({ dest: '/uploads' })| Option | Type | Description |
|---|---|---|
storage |
StorageEngine |
Custom storage engine. Defaults to MemoryStorage. |
dest |
string |
Destination directory. Uses DiskStorage with random filenames. |
fileFilter |
FileFilter |
Function to control which files are accepted. |
limits |
BusboyLimits |
Limits on incoming data (file size, file count, etc.). |
preservePath |
boolean |
Preserve the full path of the original filename. |
- Replace
@nest-lab/fastify-multerwithnestjs-busboyin your dependencies. - Replace
FastifyMulterModulewithBusboyModulein your imports. - Replace
memoryStorage/diskStorageimports — they now come fromnestjs-busboydirectly instead offastify-multer/lib.
-import { FastifyMulterModule } from '@nest-lab/fastify-multer';
-import { memoryStorage } from 'fastify-multer/lib';
+import { BusboyModule, memoryStorage } from 'nestjs-busboy';
-FastifyMulterModule.register({ ... })
+BusboyModule.register({ ... })All interceptor names and options are identical.