@elchinabilov/nestjs-media-library
v1.4.3
Published
Complete NestJS media management library with S3, image optimization, and automatic conversions
Downloads
1,780
Maintainers
Readme
@elchinabilov/nestjs-media-library
Complete NestJS media management library with S3 integration, automatic image optimization, and multiple size conversions.
Features
✅ Database Migrations - TypeORM migrations included
✅ Single/Multiple File Upload - Support for both single and multiple file uploads
✅ Retrieve Files - Get files as objects or arrays
✅ Custom Meta Data - Add custom metadata (userId, organizationId, etc.) to each file
✅ Automatic Image Optimization - Built-in image compression to WebP format
✅ Multiple Conversions - Generate thumbnails, medium, large sizes automatically
✅ AWS S3 Integration - Seamless S3 upload support
✅ Easy Integration - Simple NestJS dependency injection
✅ RESTful API - Ready-to-use controllers
Installation
npm install @elchinabilov/nestjs-media-libraryQuick Start
1. Import Module
import { Module } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm";
import { MediaLibraryModule } from "@elchinabilov/nestjs-media-library";
@Module({
imports: [
TypeOrmModule.forRoot({
// your database config
}),
MediaLibraryModule.forRoot({
disk: "s3", // or 'local'
uploadPath: "media",
maxFileSize: 10 * 1024 * 1024, // 10MB
conversions: [
{ suffix: "thumbnail", width: 150 },
{ suffix: "medium", width: 500 },
{ suffix: "large", width: 1200, height: 800 },
],
s3: {
region: "us-east-1",
bucket: "your-bucket",
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
publicUrl: "https://your-cdn.com", // optional
},
allowedMimeTypes: ["image/jpeg", "image/png", "image/webp"], // optional
}),
],
})
export class AppModule {}2. Run Media Migration
Step 1: Copy media migration into your project
Use the CLI command to copy and generate the media migration file (with an automatically appended JavaScript timestamp):
npx nestjs-media-library migration:copyOr specify a custom migrations folder:
npx nestjs-media-library migration:copy --path src/database/migrationsThis will generate a migration file like:
src/database/migrations/
└─ 1703000123456-create-media-table.tsStep 2: Run the migration
npm run migration:run3. Use in Your Service
import { Injectable } from "@nestjs/common";
import { MediaService } from "@elchinabilov/nestjs-media-library";
@Injectable()
export class YourService {
constructor(private mediaService: MediaService) {}
// Upload with custom meta data
async uploadFile(file: Express.Multer.File, userId: string, orgId: string) {
const media = await this.mediaService.uploadSingle(file, {
userId: userId,
organizationId: orgId,
category: "document",
uploadedBy: "admin",
});
console.log("Original:", media.url);
console.log("Thumbnail:", media.conversions.thumbnail);
console.log("Meta:", media.meta);
return media;
}
async uploadMultiple(files: Express.Multer.File[], projectId: string) {
return await this.mediaService.uploadMultiple(files, {
projectId: projectId,
type: "gallery",
});
}
async getMedia(id: string) {
return await this.mediaService.findOne(id);
}
// Filter by meta data
async getOrganizationMedia(orgId: string) {
return await this.mediaService.findAll({ organizationId: orgId });
}
// Update meta data
async approveDocument(mediaId: string, adminId: string) {
return await this.mediaService.updateMeta(mediaId, {
status: "approved",
approvedBy: adminId,
approvedAt: new Date().toISOString(),
});
}
async deleteMedia(id: string) {
await this.mediaService.delete(id);
}
}API Endpoints
The package provides ready-to-use REST endpoints:
Upload Single File
POST /media/upload
Content-Type: multipart/form-data
Body:
- file (form-data)
- meta (optional JSON string)
# Example with cURL:
curl -X POST http://localhost:3000/media/upload \
-F "[email protected]" \
-F 'meta={"userId":"123","organizationId":"org_456","category":"profile"}'Response:
{
"id": "uuid",
"filename": "uuid.webp",
"originalName": "photo.jpg",
"mimeType": "image/jpeg",
"size": 102400,
"path": "media/uuid.webp",
"url": "https://bucket.s3.amazonaws.com/media/uuid.webp",
"conversions": {
"thumbnail": "https://bucket.s3.amazonaws.com/media/uuid-thumbnail.webp",
"medium": "https://bucket.s3.amazonaws.com/media/uuid-medium.webp",
"large": "https://bucket.s3.amazonaws.com/media/uuid-large.webp"
},
"meta": {
"userId": "123",
"organizationId": "org_456",
"category": "profile"
},
"disk": "s3",
"createdAt": "2024-01-01T00:00:00.000Z"
}Upload Multiple Files
POST /media/upload-multiple
Content-Type: multipart/form-data
Body:
- files (form-data, multiple)
- meta (optional JSON string)Get All Media (with optional filter)
GET /media
GET /media?organizationId=org_123
GET /media?userId=user_456&category=profileGet Single Media
GET /media/:idUpdate Meta Data
PATCH /media/:id/meta
Content-Type: application/json
{
"status": "approved",
"approvedBy": "admin_123"
}Delete Media
DELETE /media/:idConfiguration Options
| Option | Type | Default | Description |
| ------------------ | -------------------- | ----------- | ----------------------------- |
| disk | 'local' \| 's3' | 'local' | Storage driver |
| uploadPath | string | 'uploads' | Upload directory path |
| maxFileSize | number | 10485760 | Max file size in bytes (10MB) |
| conversions | ConversionConfig[] | [] | Image size conversions |
| s3 | S3Config | - | AWS S3 configuration |
| allowedMimeTypes | string[] | - | Allowed file types |
Conversion Config
interface ConversionConfig {
suffix: string; // e.g., 'thumbnail', 'medium'
width: number; // Width in pixels
height?: number; // Optional height (maintains aspect ratio if omitted)
}Local Storage Setup
MediaLibraryModule.forRoot({
disk: "local",
uploadPath: "public/uploads",
conversions: [{ suffix: "thumb", width: 200 }],
});Don't forget to serve static files:
// main.ts
import { NestFactory } from "@nestjs/core";
import { NestExpressApplication } from "@nestjs/platform-express";
import { join } from "path";
async function bootstrap() {
const app = await NestFactory.create<NestExpressApplication>(AppModule);
app.useStaticAssets(join(__dirname, "..", "public"));
await app.listen(3000);
}Advanced Usage
Custom Controller
import {
Controller,
Post,
UseInterceptors,
UploadedFile,
} from "@nestjs/common";
import { FileInterceptor } from "@nestjs/platform-express";
import { MediaService } from "@elchinabilov/nestjs-media-library";
@Controller("custom")
export class CustomController {
constructor(private mediaService: MediaService) {}
@Post("avatar")
@UseInterceptors(FileInterceptor("avatar"))
async uploadAvatar(@UploadedFile() file: Express.Multer.File) {
const media = await this.mediaService.uploadSingle(file, {
type: "avatar",
category: "profile",
});
return {
avatarUrl: media.url,
thumbnailUrl: media.conversions?.thumbnail,
metadata: media.meta,
};
}
}Meta Data Usage Examples
// E-commerce: Product image with metadata
await this.mediaService.uploadSingle(file, {
productId: "prod_123",
category: "product-image",
sku: "SKU-12345",
color: "red",
position: 0,
});
// SaaS: Company logo
await this.mediaService.uploadSingle(file, {
organizationId: "org_456",
companyName: "Acme Corp",
type: "logo",
planType: "premium",
});
// Social Media: Post images
await this.mediaService.uploadMultiple(files, {
userId: "user_789",
postId: "post_123",
hashtags: ["travel", "nature"],
location: "Baku, Azerbaijan",
});
// Filter by meta
const orgMedia = await this.mediaService.findAll({
organizationId: "org_456",
});
// Update meta
await this.mediaService.updateMeta("media-id", {
status: "approved",
approvedBy: "admin_123",
approvedAt: new Date().toISOString(),
});Direct S3 Service Usage
import { S3Service } from "@elchinabilov/nestjs-media-library";
@Injectable()
export class MyService {
constructor(private s3Service: S3Service) {}
async uploadCustom(buffer: Buffer) {
return await this.s3Service.uploadFile(
buffer,
"custom/path/file.jpg",
"image/jpeg"
);
}
}Image Processing
import { ImageService } from "@elchinabilov/nestjs-media-library";
@Injectable()
export class MyService {
constructor(private imageService: ImageService) {}
async processImage(buffer: Buffer) {
// Optimize to WebP
const optimized = await this.imageService.optimizeImage(buffer);
// Create custom sizes
const conversions = await this.imageService.createConversions(buffer, [
{ suffix: "small", width: 100 },
{ suffix: "large", width: 2000 },
]);
return { optimized, conversions };
}
}Environment Variables
Create a .env file:
AWS_ACCESS_KEY_ID=your_access_key
AWS_SECRET_ACCESS_KEY=your_secret_key
AWS_REGION=us-east-1
AWS_BUCKET=your-bucket-nameLicense
MIT © Elchin Abilov
Support
For issues and questions, please open an issue on GitHub.
