Skip to main content

Get up and running with Payload Cloudinary

This guide will help you integrate Cloudinary storage into your Payload CMS project and upload your first file.
1

Install the package

Install the Payload Cloudinary plugin using your preferred package manager:
npm install payload-cloudinary
The plugin requires @payloadcms/plugin-cloud-storage as a peer dependency, which should already be available in your Payload CMS project.
2

Configure Cloudinary credentials

Add your Cloudinary credentials to your environment variables. Create or update your .env file:
.env
CLOUDINARY_CLOUD_NAME=your_cloud_name
CLOUDINARY_API_KEY=your_api_key
CLOUDINARY_API_SECRET=your_api_secret
You can find these credentials in your Cloudinary Dashboard under Dashboard > Account Details.
Never commit your .env file to version control. Add it to your .gitignore file to keep your credentials secure.
3

Add plugin to your Payload configuration

Import and configure the plugin in your payload.config.ts:
payload.config.ts
import { buildConfig } from 'payload/config';
import { cloudinaryStorage } from 'payload-cloudinary';

export default buildConfig({
  // ... your other config options
  plugins: [
    cloudinaryStorage({
      config: {
        cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
        api_key: process.env.CLOUDINARY_API_KEY,
        api_secret: process.env.CLOUDINARY_API_SECRET
      },
      collections: {
        'media': true, // Enable for your media collection
      },
      folder: 'payload-media', // Optional: Cloudinary folder name
    })
  ]
});
The plugin automatically:
  • Disables local storage for specified collections
  • Adds Cloudinary metadata fields to your media documents
  • Handles file uploads, deletions, and URL generation
If you have multiple upload collections (like media and documents), you can enable Cloudinary for each:
collections: {
  'media': true,
  'documents': true,
}
4

Upload a test file

Start your Payload dev server and test the integration:
Terminal
npm run dev
Then upload a file through the Payload admin panel:
  1. Navigate to your Media collection in the admin UI
  2. Click Create New
  3. Upload an image or PDF file
  4. Save the document
The file will be automatically uploaded to Cloudinary and stored in the folder you specified (default: payload-media).
5

Access Cloudinary metadata

After uploading, your media documents will include comprehensive Cloudinary metadata:
const doc = await payload.findByID({
  collection: 'media',
  id: 'your-doc-id',
});

// Access Cloudinary metadata
console.log(doc.cloudinary);
The cloudinary field contains:
{
  public_id: string;        // Cloudinary public ID
  resource_type: string;    // 'image', 'video', or 'raw'
  format: string;           // File extension (jpg, png, pdf, etc.)
  secure_url: string;       // Full HTTPS URL
  bytes: number;            // File size in bytes
  created_at: string;       // Upload timestamp
  version: string;          // Current version number
  version_id: string;       // Current version ID
  width?: number;           // For images and videos
  height?: number;          // For images and videos
  duration?: number;        // For videos only
  pages?: number;           // For PDFs only
  selected_page?: number;   // For PDFs only (thumbnail page)
}
Use the public_id to build custom Cloudinary transformation URLs in your frontend:
const transformedUrl = `https://res.cloudinary.com/${cloudName}/image/upload/w_400,h_300,c_fill/${doc.cloudinary.public_id}.${doc.cloudinary.format}`;

Next steps

Now that you have Payload Cloudinary working, explore these advanced features:

Basic Configuration

Customize folder structure, public IDs, and storage options

Custom Fields

Add custom fields like alt text, captions, and tags to your media

PDF Support

Enable PDF thumbnail generation and page selection

Versioning

Track file changes with version history

Troubleshooting

The plugin sets disableLocalStorage: true automatically. If files are still being saved locally:
  • Verify the plugin is properly configured in payload.config.ts
  • Ensure the collection slug in collections matches your Media collection exactly
  • Restart your dev server after making configuration changes
  • Check that you don’t have conflicting upload configurations
If you’re getting authentication errors:
  • Double-check your credentials in the Cloudinary dashboard
  • Ensure there are no extra spaces in your .env file
  • Verify environment variables are loaded correctly with console.log(process.env.CLOUDINARY_CLOUD_NAME)
  • Try regenerating your API secret if the issue persists
For newer Cloudinary accounts using Dynamic Folder Mode:
  • The plugin automatically supports Dynamic Folder Mode by default
  • Files will appear in the folder specified by the folder option
  • If assets aren’t showing up in the Media Library, verify the folder parameter in your config
  • You can disable Dynamic Folder Mode support with supportDynamicFolderMode: false if needed
If your custom fields aren’t appearing:
  • Verify the collection slug in your plugin config matches exactly with your Media collection slug
  • Ensure the plugin is registered before collections are processed
  • Try restarting your development server
  • Check for field name conflicts with existing fields
  • Add debug logging to verify fields are being added:
    onInit: async (payload) => {
      console.log('Media fields:', 
        payload.collections['media'].config.fields.map(f => f.name)
      );
    }
    
For PDF files:
  • Ensure PDF support is not disabled: enablePDFThumbnails should not be set to false
  • Check that the cloudinary.public_id field is populated after upload
  • Verify the PDF was successfully uploaded to Cloudinary
  • The pages field should be automatically populated with the page count
  • Use selected_page to choose which page to display as a thumbnail (defaults to 1)
For more detailed troubleshooting, check the complete configuration documentation or reach out to Syed Muzamil for support.

Build docs developers (and LLMs) love