@api-buddy/cloudinary v0.4.108
@api-buddy/cloudinary
A comprehensive Cloudinary integration for Next.js applications, providing a simple and type-safe way to upload, transform, and deliver images and videos.
Features
- 🚀 Easy Setup: Get started quickly with a few simple steps
- 🔒 Type-Safe: Full TypeScript support for all Cloudinary options and responses
- ⚡ Performance Optimized: Automatic image optimization and responsive images
- 🎣 React Hooks: Custom hooks for easy file uploads and media management
- 🖼️ Components: Pre-built React components for images and videos
- 🛠 CLI Tool: Quick project setup with the included CLI
- 🔄 Server & Client Support: Works with both server components and client components
- 📱 Responsive Images: Automatic srcset generation for responsive images
- 🎥 Video Support: Upload, transform, and deliver videos with ease
Installation
# Using npm
npm install @api-buddy/cloudinary cloudinary
# Using yarn
yarn add @api-buddy/cloudinary cloudinary
# Using pnpm
pnpm add @api-buddy/cloudinary cloudinary
If you're using TypeScript, you'll also want to install the Cloudinary types:
npm install --save-dev @types/cloudinary
Quick Start
1. Set Up Environment Variables
Create a .env.local
file in your project root and add your Cloudinary credentials:
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME=your_cloud_name
NEXT_PUBLIC_CLOUDINARY_API_KEY=your_api_key
CLOUDINARY_API_SECRET=your_api_secret
NEXT_PUBLIC_CLOUDINARY_UPLOAD_PRESET=your_upload_preset
2. Set Up the Cloudinary Provider
Wrap your application with the CloudinaryProvider
in your root layout:
// app/layout.tsx
'use client';
import { CloudinaryProvider } from '@api-buddy/cloudinary';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
<CloudinaryProvider
config={{
// Optional: Configure default settings here
cloudName: process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME,
apiKey: process.env.NEXT_PUBLIC_CLOUDINARY_API_KEY,
apiSecret: process.env.CLOUDINARY_API_SECRET,
uploadPreset: process.env.NEXT_PUBLIC_CLOUDINARY_UPLOAD_PRESET,
}}
>
{children}
</CloudinaryProvider>
</body>
</html>
);
}
3. Upload Files
Create an API route to handle file uploads:
// app/api/upload/route.ts
import { NextResponse } from 'next/server';
import { upload } from '@api-buddy/cloudinary';
export async function POST(request: Request) {
try {
const formData = await request.formData();
const file = formData.get('file') as File;
if (!file) {
return NextResponse.json(
{ success: false, error: 'No file provided' },
{ status: 400 }
);
}
// Convert the file to a buffer
const buffer = Buffer.from(await file.arrayBuffer());
// Upload to Cloudinary
const result = await upload(buffer, {
folder: 'uploads',
resourceType: 'auto',
public_id: file.name.replace(/\.[^/.]+$/, ''), // Remove file extension
filename_override: file.name,
context: {
filename: file.name,
format: file.type,
size: file.size,
},
});
return NextResponse.json({ success: true, data: result });
} catch (error) {
console.error('Upload error:', error);
return NextResponse.json(
{ success: false, error: 'Failed to upload file' },
{ status: 500 }
);
}
}
4. Use the useCloudinaryUpload Hook
'use client';
import { useCloudinaryUpload } from '@api-buddy/cloudinary';
export default function UploadForm() {
const { uploadFile, isUploading, progress, error } = useCloudinaryUpload({
options: {
folder: 'images',
resourceType: 'image',
},
onSuccess: (result) => {
console.log('Upload successful:', result);
},
onError: (error) => {
console.error('Upload error:', error);
},
});
const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (file) {
await uploadFile(file);
}
};
return (
<div className="p-6 max-w-md mx-auto bg-white rounded-xl shadow-md">
<h2 className="text-xl font-semibold mb-4">Upload an Image</h2>
<div className="mb-4">
<input
type="file"
accept="image/*"
onChange={handleFileChange}
disabled={isUploading}
className="block w-full text-sm text-gray-500
file:mr-4 file:py-2 file:px-4
file:rounded-md file:border-0
file:text-sm file:font-semibold
file:bg-blue-50 file:text-blue-700
hover:file:bg-blue-100"
/>
</div>
{isUploading && (
<div className="w-full bg-gray-200 rounded-full h-2.5">
<div
className="bg-blue-600 h-2.5 rounded-full"
style={{ width: `${progress}%` }}
></div>
<p className="text-sm text-gray-600 mt-1">Uploading: {progress}%</p>
</div>
)}
{error && (
<div className="mt-4 p-3 bg-red-100 text-red-700 rounded-md">
Error: {error.message}
</div>
)}
</div>
);
}
5. Display Images
import { CloudinaryImage } from '@api-buddy/cloudinary';
export default function ProfileImage({ publicId }: { publicId: string }) {
return (
<div className="w-32 h-32 rounded-full overflow-hidden">
<CloudinaryImage
publicId={publicId}
alt="Profile image"
width={128}
height={128}
className="w-full h-full object-cover"
transformation={[
{ width: 256, height: 256, crop: 'thumb', gravity: 'face' },
{ radius: 'max' },
]}
/>
</div>
);
}
CLI Setup
For a quick setup, use the included CLI:
npx @api-buddy/cloudinary setup
This will: 1. Install required dependencies 2. Set up environment variables 3. Create example components and API routes 4. Configure your Next.js app to use Cloudinary
API Reference
CloudinaryProvider
A context provider that makes the Cloudinary client available throughout your application.
Props
config
: Configuration objectcloudName
: Your Cloudinary cloud name (required)apiKey
: Your Cloudinary API key (optional, defaults toprocess.env.NEXT_PUBLIC_CLOUDINARY_API_KEY
)apiSecret
: Your Cloudinary API secret (optional, defaults toprocess.env.CLOUDINARY_API_SECRET
)uploadPreset
: Your Cloudinary upload preset (optional)defaultUploadOptions
: Default options for all uploads
useCloudinary()
A hook to access the Cloudinary client from the nearest CloudinaryProvider
.
Returns
client
: The Cloudinary client instanceconfig
: The current Cloudinary configuration
useCloudinaryUpload(options)
A hook for handling file uploads to Cloudinary.
Parameters
options
: Upload optionsoptions
: Default upload options for all uploadsonSuccess
: Callback when an upload succeedsonError
: Callback when an upload failsonProgress
: Callback with upload progress (0-100)
Returns
uploadFile
: Function to upload a single fileuploadFiles
: Function to upload multiple filesisUploading
: Boolean indicating if an upload is in progressprogress
: Current upload progress (0-100)error
: Error object if an upload failedreset
: Function to reset the hook state
CloudinaryImage
A React component for displaying Cloudinary images with automatic optimization.
Props
publicId
: The public ID of the image (required)alt
: Alternative text for the image (required)width
: Width of the imageheight
: Height of the imageclassName
: CSS class namestyle
: Inline stylesloading
: Loading behavior (lazy
oreager
)transformation
: Array of Cloudinary transformationsformat
: Image format to convert toquality
: Image quality (1-100)responsive
: Whether to generate responsive imagessizes
: Sizes attribute for responsive imagessrcSet
: Custom srcset for responsive imagesonLoad
: Callback when the image loadsonError
: Callback when the image fails to load
CloudinaryVideo
A React component for displaying Cloudinary videos.
Props
publicId
: The public ID of the video (required)width
: Width of the video playerheight
: Height of the video playerclassName
: CSS class namestyle
: Inline stylesautoPlay
: Whether to autoplay the videoloop
: Whether to loop the videomuted
: Whether to mute the videocontrols
: Whether to show video controlsposter
: URL of the poster imagetransformation
: Array of Cloudinary transformationsonPlay
: Callback when the video starts playingonPause
: Callback when the video is pausedonEnded
: Callback when the video endsonError
: Callback when the video fails to load
upload(file, options)
Upload a file to Cloudinary.
Parameters
file
: File to upload (Buffer, ReadStream, or base64 string)options
: Upload options (see Cloudinary documentation)
Returns
A promise that resolves to the upload result.
deleteFile(publicId, options)
Delete a file from Cloudinary.
Parameters
publicId
: The public ID of the file to deleteoptions
: Delete optionsresourceType
: Type of resource (image
,video
,raw
, orauto
)type
: The type of the resourceinvalidate
: Whether to invalidate the CDN cache
Returns
A promise that resolves to the delete result.
getUrl(publicId, options)
Generate a URL for a Cloudinary resource.
Parameters
publicId
: The public ID of the resourceoptions
: URL and transformation optionstransformation
: Array of Cloudinary transformationsresourceType
: Type of resource (image
,video
,raw
, orauto
)type
: The type of the resourceformat
: Format to convert the resource tosecure
: Whether to use HTTPSsignUrl
: Whether to sign the URLversion
: The version of the resource
Returns
The generated URL as a string.
Examples
Uploading a File
import { upload } from '@api-buddy/cloudinary';
// In an API route or server component
const file = // your file buffer or stream
const result = await upload(file, {
folder: 'uploads',
resourceType: 'auto',
public_id: 'my-file',
});
console.log('File uploaded:', result.url);
Using Transformations
import { CloudinaryImage } from '@api-buddy/cloudinary';
function ProductImage({ publicId }: { publicId: string }) {
return (
<CloudinaryImage
publicId={publicId}
alt="Product image"
width={400}
height={400}
transformation={[
{ width: 800, height: 800, crop: 'fill' },
{ effect: 'sharpen' },
{ quality: 'auto' },
]}
/>
);
}
Responsive Images
import { CloudinaryImage } from '@api-buddy/cloudinary';
function HeroImage({ publicId }: { publicId: string }) {
return (
<CloudinaryImage
publicId={publicId}
alt="Hero image"
width={1200}
height={630}
className="w-full h-auto"
responsive
sizes="(max-width: 768px) 100vw, 50vw"
transformation={[
{ width: 1200, height: 630, crop: 'fill' },
{ quality: 'auto' },
]}
/>
);
}
Error Handling
All functions throw a CloudinaryError
when something goes wrong. You can catch and handle these errors:
try {
await upload(file, options);
} catch (error) {
if (error.name === 'CloudinaryError') {
console.error('Cloudinary error:', error.message);
// Handle specific error cases
if (error.code === 'LIMIT_FILE_SIZE') {
// Handle file size limit exceeded
} else if (error.code === 'UNAUTHORIZED') {
// Handle authentication error
} else {
// Handle other errors
}
} else {
// Handle non-Cloudinary errors
console.error('Unexpected error:', error);
}
}
Contributing
Contributions are welcome! Please open an issue or submit a pull request.
License
MIT
Acknowledgments
- Cloudinary - Cloud-based image and video management
- @cloudinary/url-builder - Official Cloudinary URL builder
- @cloudinary/react - Official Cloudinary React components