Create a .env.local file in the root directory and add:
# Cloudinary API Credentials
CLOUDINARY_CLOUD_NAME=your_cloud_name
CLOUDINARY_API_KEY=your_api_key
CLOUDINARY_API_SECRET=your_api_secret
# Optional: Cloudinary URL (alternative)
CLOUDINARY_URL=cloudinary://your_api_key:your_api_secret@your_cloud_name- Go to Cloudinary Console
- Sign up or log in to your account
- In the Account Details section, find:
- Cloud Name: Your unique cloud identifier
- API Key: Your API key
- API Secret: Your API secret (keep this private!)
- Add
.env.localto your.gitignore - Store credentials in environment variables
- Use the CLOUDINARY_URL format only for local development
The backend Cloudinary configuration is located at:
src/config/cloudinary.ts- Cloudinary SDK initializationsrc/api/middleware/upload.middleware.ts- File upload handlingsrc/modules/images/controllers/ImageController.ts- Image management endpoints
The frontend upload and image display components are located at:
src/app/components/shared/ImageUpload.tsx- Single image upload componentsrc/app/components/shared/MultiImageUpload.tsx- Multiple image upload componentsrc/app/components/shared/ResponsiveImage.tsx- Responsive image display component
POST /api/v1/images/upload?type=avatar&width=200&height=200
Content-Type: multipart/form-data
Form Data:
- image: [file]
- folder: "tnp-portal/users" (optional)
- type: "avatar" | "logo" | "banner" | "thumbnail" | "gallery"POST /api/v1/images/upload-multiple
Content-Type: multipart/form-data
Form Data:
- images: [file1, file2, ...]
- folder: "tnp-portal/gallery" (optional)GET /api/v1/images/responsive?publicId=tnp-portal/users/123&type=avatar&width=200&height=200DELETE /api/v1/images/public-idimport ImageUpload from '@/app/components/shared/ImageUpload';
<ImageUpload
onSuccess={(data) => console.log(data)}
onError={(error) => console.error(error)}
type="avatar"
folder="tnp-portal/users"
/>import MultiImageUpload from '@/app/components/shared/MultiImageUpload';
<MultiImageUpload
maxFiles={5}
onSuccess={(images) => console.log(images)}
onError={(error) => console.error(error)}
folder="tnp-portal/gallery"
/>import ResponsiveImage from '@/app/components/shared/ResponsiveImage';
<ResponsiveImage
publicId="tnp-portal/users/123"
type="avatar"
alt="User profile"
className="rounded-full"
/>When storing image URLs in database, store:
public_id: Cloudinary public ID (for deletion/updates)url: Original secure URLtype: Image category (avatar, logo, banner, etc.)uploadedAt: Timestamp of uploaduploadedBy: User ID who uploaded
Example Schema:
model Image {
id String @id @default(cuid())
publicId String @unique
url String
type String // 'avatar' | 'logo' | 'banner' | 'thumbnail' | 'gallery'
entityType String // 'user' | 'company' | 'drive' | 'event' | 'achievement'
entityId String // ID of the entity the image belongs to
uploadedAt DateTime @default(now())
uploadedBy String? // User ID
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([publicId])
@@index([entityType, entityId])
}- Size: 200x200px (displayed), stored at 400x400px
- Crop: Face-focused with gravity
- Format: WEBP/JPEG
- Use for: Student profiles, staff photos
- Size: 200x200px to 400x400px
- Crop: Centered with white background
- Format: WEBP/PNG
- Use for: Company branding, recruitment partners
- Size: 1200x400px responsive
- Crop: Center-focused
- Format: WEBP/JPEG
- Use for: Placement drives, event announcements
- Size: 300x200px
- Crop: Auto-focused
- Format: WEBP/JPEG
- Use for: Achievement gallery, notices
- Size: 500x500px to 1000x1000px
- Crop: Aspect ratio preserved
- Format: WEBP/JPEG
- Use for: Achievement photos, event gallery
✓ Auto-format to WEBP for modern browsers ✓ Quality: Auto-optimized per device ✓ Lazy loading support ✓ Responsive breakpoints (mobile/tablet/desktop) ✓ CDN delivery for fast loading ✓ Automatic compression ✓ Transformation caching
- Check file size (max 10MB)
- Verify file type (JPEG, PNG, WebP, GIF)
- Check API credentials in environment variables
- Review Cloudinary quota usage
- Ensure auto-format is enabled
- Check network tab for actual image size
- Consider using smaller dimensions for thumbnails
- Enable CDN caching
- Increase quality parameter in transformations
- Use AVIF format for modern browsers
- Reduce compression for high-quality needs
For more information, visit Cloudinary Documentation