Skip to content

UtilKit/nestjs-minio-backend

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

30 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

NestJS MinIO Backend

NPM Version Downloads Stats License TypeScript NestJS MinIO

A powerful and flexible NestJS module for integrating MinIO object storage into your NestJS applications. This package provides a seamless way to interact with MinIO, an open-source object storage service compatible with Amazon S3.

Table of Contents

Features

  • πŸš€ Easy integration with NestJS applications
  • 🎯 Powerful decorators for blazing-fast implementation
    • @FileUpload() - Handles multiple file uploads with built-in validation
    • @FileField() - Swagger-ready DTO field decorator
    • @FileSchemaField() - Mongoose schema integration for file fields
  • πŸ—ƒοΈ @FileColumn() decorator for TypeORM or any class-based model
  • πŸ“ Complete MinIO operations support (upload, download, delete, etc.)
  • πŸ”§ Configurable module options
  • 🎯 TypeScript support
  • πŸ“ Swagger documentation support
  • πŸ”„ RxJS integration
  • 🧩 Optional @nestjs/mongoose integration (only required if you use @FileSchemaField)
  • πŸ€– Automatic presigned URL detection even for raw QueryBuilder results

Installation

npm install nestjs-minio-backend

Requirements

  • Node.js >= 20.15.0
  • NestJS >= 11.0.0
  • MinIO Server (running instance)

Peer Dependencies

This module requires the following peer dependencies:

{
  "@nestjs/common": "^11.0.12",
  "@nestjs/core": "^11.0.12",
  "minio": "^8.0.5",
  "rxjs": "^7.8.2",
  "@nestjs/mongoose": "^11.0.2",
  "@nestjs/platform-express": "^11.0.12",
  "@nestjs/swagger": "^11.0.7",
  "class-validator": "^0.14.1"
}

Quick Start (Using Decorators)

  1. First, set up your MinIO configuration:

Create a config/minio.config.ts file:

import { registerAs } from '@nestjs/config';

export default registerAs('minio', () => ({
  endPoint: process.env.MINIO_ENDPOINT || 'localhost:9000', // Format: "host" or "host:port"
  externalEndPoint:
    process.env.MINIO_EXTERNAL_ENDPOINT ||
    process.env.MINIO_ENDPOINT ||
    'localhost:9000', // Format: "host" or "host:port"
  useSSL: process.env.MINIO_USE_HTTPS === 'true',
  externalUseSSL: process.env.MINIO_EXTERNAL_ENDPOINT_USE_HTTPS === 'true',
  accessKey: process.env.MINIO_ACCESS_KEY || 'minioadmin',
  secretKey: process.env.MINIO_SECRET_KEY || 'minioadmin',
  urlExpiryHours: parseInt(process.env.MINIO_URL_EXPIRY_HOURS || '2', 10),
  buckets: {
    private: [
      process.env.MINIO_MEDIA_FILES_BUCKET || 'media-files-bucket',
      process.env.MINIO_CHAIN_ICONS_BUCKET || 'chain-icons',
    ],
    public: [process.env.MINIO_STATIC_FILES_BUCKET || 'static-files-bucket'],
  },
  region: process.env.MINIO_REGION,
}));

Create a .env file in your project root:

MINIO_ENDPOINT=minio:9000
MINIO_EXTERNAL_ENDPOINT=minio.example.com:9000
MINIO_USE_HTTPS=false
MINIO_ACCESS_KEY=your-access-key
MINIO_SECRET_KEY=your-secret-key
MINIO_MEDIA_FILES_BUCKET=media-files-bucket
MINIO_STATIC_FILES_BUCKET=static-files-bucket
MINIO_URL_EXPIRY_HOURS=2

Then, in your app.module.ts:

import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { MinioModule } from 'nestjs-minio-backend';
import minioConfig from './config/minio.config';

@Module({
  imports: [
    ConfigModule.forRoot({
      load: [minioConfig],
    }),
    MinioModule.forRootAsync({
      inject: [ConfigService],
      useFactory: (configService: ConfigService) => configService.get('minio'),
    }),
  ],
})
export class AppModule {}

This configuration approach provides:

  • πŸ” Environment-based configuration
  • 🎯 Type-safe configuration using TypeScript
  • πŸ”„ Default values for local development
  • πŸ“ Organized bucket management
  • 🌐 Support for different endpoints (internal/external)
  1. Create your DTO with file field:
import { FileField } from 'nestjs-minio-backend';

export class CreateUserDto {
  @FileField({
    bucketName: 'profiles',
    required: true,
    description: 'User profile picture'
  })
  profilePicture: Express.Multer.File;
}
  1. Use the FileUpload decorator in your controller:
import { FileUpload } from 'nestjs-minio-backend';
import { CreateUserDto } from './dto/create-user.dto';

@Controller('users')
export class UserController {
  @Post()
  @FileUpload([
    { name: 'profilePicture', bucketName: 'profiles', required: true }
  ])
  async createUser(@Body() createUserDto: CreateUserDto) {
    // The file is automatically uploaded to MinIO
    // You can access the file URL from the DTO
    return createUserDto;
  }

  @Post('multiple')
  @FileUpload([
    { name: 'documents', bucketName: 'docs', maxCount: 3 }
  ])
  async uploadMultiple(@UploadedFiles() files: Array<Express.Multer.File>) {
    return files; // Files are automatically uploaded to MinIO
  }
}
  1. (Optional) Add file fields to your persistence models:

TypeORM example

import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
import { FileColumn } from 'nestjs-minio-backend';

@Entity()
export class User {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @FileColumn({ bucketName: 'profiles' })
  @Column({ nullable: true })
  avatar?: string; // Stores the MinIO object path (bucket/objectName)
}

Mongoose example

import { FileSchemaField } from 'nestjs-minio-backend';

@Schema()
export class User {
  @FileSchemaField({
    bucketName: 'profiles',
    required: true
  })
  avatar: string; // Automatically stores the MinIO object URL
}

These decorators provide:

  • πŸš€ Zero-configuration file uploads
  • πŸ“ Automatic Swagger documentation
  • βœ… Built-in validation
  • πŸ”„ Seamless MongoDB integration
  • πŸ€– Automatic presigned URL generation even for raw QueryBuilder objects (bucket names are auto-detected from your MinIO config)
  • 🎯 Type safety with TypeScript
  • 🧩 Optional Mongoose dependency (install @nestjs/mongoose only if you plan to use @FileSchemaField)

Configuration

The module accepts the following configuration options:

interface IMinioModuleOptions {
  // Required options
  endPoint: string;          // MinIO server endpoint (format: "host" or "host:port", e.g., "minio:9000")
  useSSL: boolean;          // Whether to use SSL for connection
  accessKey: string;        // MinIO access key
  secretKey: string;        // MinIO secret key
  urlExpiryHours: number;   // Expiry time for signed URLs in hours

  // Optional options
  region?: string;          // MinIO region
  externalEndPoint?: string; // External endpoint for public access (format: "host" or "host:port")
  externalUseSSL?: boolean; // Whether to use SSL for external endpoint

  // Bucket configuration
  buckets: {
    private: string[];      // Array of private bucket names
    public: string[];       // Array of public bucket names
  };
}

Configuration Example

const minioConfig: IMinioModuleOptions = {
  endPoint: 'minio.example.com:9000', // Port included in endpoint
  useSSL: false,
  accessKey: 'your-access-key',
  secretKey: 'your-secret-key',
  urlExpiryHours: 2,
  
  // Optional settings
  region: 'us-east-1',
  externalEndPoint: 'public.minio.example.com:9000', // Port included in endpoint
  externalUseSSL: true,
  
  // Bucket configuration
  buckets: {
    private: [
      'media-files-bucket',
      'user-uploads'
    ],
    public: [
      'static-files-bucket',
      'public-assets'
    ]
  }
};

Environment Variables Example

# Required settings
MINIO_ENDPOINT=minio:9000
MINIO_USE_HTTPS=false
MINIO_ACCESS_KEY=your-access-key
MINIO_SECRET_KEY=your-secret-key
MINIO_URL_EXPIRY_HOURS=2

# Optional settings
MINIO_REGION=us-east-1
MINIO_EXTERNAL_ENDPOINT=minio.example.com:9000
MINIO_EXTERNAL_ENDPOINT_USE_HTTPS=true

# Bucket configuration
MINIO_MEDIA_FILES_BUCKET=media-files-bucket
MINIO_STATIC_FILES_BUCKET=static-files-bucket

Key Features of the Configuration

  • πŸ” Dual Endpoint Support: Configure both internal and external endpoints for flexible access
  • 🌐 SSL Configuration: Separate SSL settings for internal and external endpoints
  • ⏱️ URL Expiry: Configure signed URL expiration time
  • πŸ“ Bucket Organization: Separate configuration for private and public buckets
  • πŸ”„ Default Values: Sensible defaults for local development
  • πŸ›‘οΈ Type Safety: Full TypeScript support with interface definitions

Manual Implementation (Without Decorators)

If you prefer more control over the file handling process, you can use the MinioService directly:

import { MinioService } from 'nestjs-minio-backend';

@Injectable()
export class YourService {
  constructor(private readonly minioService: MinioService) {}

  async uploadFile(file: Express.Multer.File) {
    const bucketName = 'your-bucket';
    const objectName = `${Date.now()}-${file.originalname}`;
    
    await this.minioService.upload(bucketName, objectName, file.buffer);
    return { objectName };
  }
}

Manual File Upload Example

@Post('upload')
@UseInterceptors(FileInterceptor('file'))
async uploadFile(@UploadedFile() file: Express.Multer.File) {
  const bucketName = 'my-bucket';
  const objectName = `${Date.now()}-${file.originalname}`;
  
  await this.minioService.upload(bucketName, objectName, file.buffer);
  
  return {
    message: 'File uploaded successfully',
    objectName,
  };
}

Manual File Download Example

@Get('download/:objectName')
async downloadFile(@Param('objectName') objectName: string, @Res() res: Response) {
  const bucketName = 'my-bucket';
  const fileBuffer = await this.minioService.download(bucketName, objectName);
  
  res.send(fileBuffer);
}

API Reference

Decorators

@FileUpload()

Handles file uploads with automatic MinIO integration.

@FileUpload([
  { 
    name: string,           // Field name in the request
    bucketName: string,     // MinIO bucket name
    required?: boolean,     // Whether the file is required
    maxCount?: number,      // Maximum number of files
    maxSize?: number,       // Maximum file size in bytes
    mimeTypes?: string[]    // Allowed MIME types
  }
])

@FileField()

Swagger-ready DTO field decorator for file uploads.

@FileField({
  bucketName: string,       // MinIO bucket name
  required?: boolean,       // Whether the field is required
  description?: string      // Swagger description
})

@FileSchemaField()

Mongoose schema integration for file fields (wraps @Prop plus @FileColumn metadata).

@FileSchemaField({
  bucketName: string,       // MinIO bucket name
  required?: boolean        // Whether the field is required
})

@FileColumn()

Database-agnostic decorator for marking entity properties that store MinIO object references. Works with TypeORM, Mongoose, or any class-based model.

@FileColumn({
  bucketName?: string        // Optionally enforce a specific bucket
})

Contributing

  1. Fork it (https://github.com/UtilKit/nestjs-minio-backend/fork)
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -am 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Create a new Pull Request

License

This project is licensed under the MIT License - see the LICENSE file for details.

Author

Mishhub

Support

About

A powerful and flexible NestJS module for integrating MinIO object storage into your NestJS applications.

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published