Skip to main content
Technology & EngineeringStorage Services206 lines

Cloudinary

Build with Cloudinary for image and video management. Use this skill when the

Quick Summary27 lines
You are a media specialist who integrates Cloudinary into projects. Cloudinary is
a cloud-based media management platform for image and video upload, transformation,
optimization, and delivery via CDN.

## Key Points

- Always use `f_auto,q_auto` for automatic format and quality optimization
- Use `gravity: 'auto'` for AI-based smart cropping
- Use upload presets for client-side uploads — restricts what can be uploaded
- Use `CldImage` in Next.js — it integrates with next/image optimization
- Use folders and tags to organize assets
- Set `crop: 'limit'` on upload to cap maximum dimensions
- Serving original unoptimized images — always apply `q_auto,f_auto`
- Generating transformation URLs client-side with API secret exposed
- Not using responsive sizes — serve different sizes for different viewports
- Uploading duplicate images — use `overwrite: true` or check `public_id`
- Storing Cloudinary URLs in the database — store `public_id` and generate URLs
- Not setting upload limits — allow arbitrarily large file uploads

## Quick Example

```bash
npm install cloudinary
npm install next-cloudinary  # For Next.js
```
skilldb get storage-services-skills/CloudinaryFull skill: 206 lines
Paste into your CLAUDE.md or agent config

Cloudinary Integration

You are a media specialist who integrates Cloudinary into projects. Cloudinary is a cloud-based media management platform for image and video upload, transformation, optimization, and delivery via CDN.

Core Philosophy

URL-based transformations

Cloudinary transforms images and videos through URL parameters — resize, crop, format-convert, add overlays, apply effects — all by modifying the delivery URL. No server-side image processing needed.

Automatic optimization

Cloudinary's f_auto and q_auto parameters automatically deliver the best format (WebP, AVIF) and quality for each browser. You don't manage format negotiation — Cloudinary handles it at the CDN edge.

Upload once, transform infinitely

Upload the original asset once. Generate any variation (thumbnail, hero, social card, video preview) on the fly via URL transformations. No need to pre-generate sizes.

Setup

Install

npm install cloudinary
npm install next-cloudinary  # For Next.js

Initialize

import { v2 as cloudinary } from 'cloudinary';

cloudinary.config({
  cloud_name: process.env.CLOUDINARY_CLOUD_NAME!,
  api_key: process.env.CLOUDINARY_API_KEY!,
  api_secret: process.env.CLOUDINARY_API_SECRET!,
});

Key Techniques

Upload

// Server-side upload
const result = await cloudinary.uploader.upload(filePath, {
  folder: 'posts',
  public_id: 'my-image',
  transformation: [{ width: 2000, crop: 'limit' }], // Max 2000px wide on upload
  tags: ['blog', 'hero'],
});
// result.secure_url, result.public_id, result.width, result.height

// Upload from buffer
const result = await cloudinary.uploader.upload_stream(
  { folder: 'avatars', public_id: userId },
  (error, result) => { /* handle */ }
).end(buffer);

// Upload from URL
const result = await cloudinary.uploader.upload('https://example.com/photo.jpg', {
  folder: 'imports',
});

// Signed upload preset (client-side uploads)
const preset = await cloudinary.api.create_upload_preset({
  name: 'user_avatars',
  folder: 'avatars',
  allowed_formats: ['jpg', 'png', 'webp'],
  transformation: [{ width: 500, height: 500, crop: 'fill', gravity: 'face' }],
});

URL transformations

// Generate transformation URL
const url = cloudinary.url('posts/hero-image', {
  width: 800,
  height: 400,
  crop: 'fill',
  gravity: 'auto',       // AI-based smart crop
  quality: 'auto',       // Automatic quality
  fetch_format: 'auto',  // WebP/AVIF auto
});

// Thumbnail
const thumb = cloudinary.url('posts/hero-image', {
  width: 150,
  height: 150,
  crop: 'thumb',
  gravity: 'face',
});

// Text overlay
const social = cloudinary.url('posts/hero-image', {
  transformation: [
    { width: 1200, height: 630, crop: 'fill' },
    { overlay: { text: 'My Blog Post Title', font_family: 'Arial', font_size: 48 },
      gravity: 'south', y: 40, color: 'white' },
  ],
});

// Raw URL pattern
// https://res.cloudinary.com/{cloud}/image/upload/w_800,h_400,c_fill,g_auto,q_auto,f_auto/posts/hero-image

Next.js integration (next-cloudinary)

import { CldImage, CldUploadWidget } from 'next-cloudinary';

// Optimized image component
function HeroImage({ publicId }: { publicId: string }) {
  return (
    <CldImage
      src={publicId}
      width={1200}
      height={630}
      crop="fill"
      gravity="auto"
      alt="Hero image"
      sizes="100vw"
    />
  );
}

// Upload widget
function ImageUploader({ onUpload }: { onUpload: (url: string) => void }) {
  return (
    <CldUploadWidget
      uploadPreset="user_avatars"
      onSuccess={(result) => {
        if (typeof result.info !== 'string') {
          onUpload(result.info.secure_url);
        }
      }}
    >
      {({ open }) => <button onClick={() => open()}>Upload Image</button>}
    </CldUploadWidget>
  );
}

Video

// Video transformation
const videoUrl = cloudinary.url('videos/intro', {
  resource_type: 'video',
  width: 720,
  crop: 'scale',
  quality: 'auto',
  fetch_format: 'auto', // MP4/WebM auto
});

// Video thumbnail
const poster = cloudinary.url('videos/intro', {
  resource_type: 'video',
  format: 'jpg',
  transformation: [{ width: 1280, height: 720, crop: 'fill' }],
});

Delete and manage

// Delete
await cloudinary.uploader.destroy('posts/old-image');

// Rename
await cloudinary.uploader.rename('posts/old-name', 'posts/new-name');

// List resources
const { resources } = await cloudinary.api.resources({
  type: 'upload',
  prefix: 'posts/',
  max_results: 50,
});

Best Practices

  • Always use f_auto,q_auto for automatic format and quality optimization
  • Use gravity: 'auto' for AI-based smart cropping
  • Use upload presets for client-side uploads — restricts what can be uploaded
  • Use CldImage in Next.js — it integrates with next/image optimization
  • Use folders and tags to organize assets
  • Set crop: 'limit' on upload to cap maximum dimensions

Anti-Patterns

  • Serving original unoptimized images — always apply q_auto,f_auto
  • Generating transformation URLs client-side with API secret exposed
  • Not using responsive sizes — serve different sizes for different viewports
  • Uploading duplicate images — use overwrite: true or check public_id
  • Storing Cloudinary URLs in the database — store public_id and generate URLs
  • Not setting upload limits — allow arbitrarily large file uploads

Install this skill directly: skilldb add storage-services-skills

Get CLI access →