Migrating Images to Cloudinary: How I Reduced My Repo Size by 99.7% and Supercharged My Website

Migrating Images to Cloudinary: How I Reduced My Repo Size by 99.7% and Supercharged My Website

Why I ditched local images and migrated everything to Cloudinary CDN in Next.js: less bloat, more speed, and a way more professional workflow.

The Local Images Problem

A month ago, my Next.js portfolio was like most others: loading images from /public/images. The result?

I wanted to fix this at the root, scale without fear, and have a site worthy of 2025. The solution: migrate everything to Cloudinary.


Why Cloudinary? (And Not Another CDN)

The Downside of Local Images:

REAL Advantages of Cloudinary:


Step by Step: How I Migrated Everything

1. Initial Setup

First, the dependencies:

npm install cloudinary next-cloudinary

And your secrets in .env.local:

NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME=your_cloud_name
CLOUDINARY_API_KEY=xxxx
CLOUDINARY_API_SECRET=xxxx

2. Custom Image Component

I created a component that automatically generates the Cloudinary src, falls back to the local image if it fails, and leverages Next.js optimization:

// components/common/SimpleCloudinaryImage.tsx
const getCloudinaryUrl = (imageSrc: string) => {
  const pathWithoutImages = imageSrc.replace('/images/', '').replace(/\.[^/.]+$/, '');
  const cloudinaryId = `blacro-portfolio/${pathWithoutImages}`;
  return `https://res.cloudinary.com/dm9driroe/image/upload/v1/${cloudinaryId}`;
};

And the import replacement:

// Before
import Image from 'next/image';

// After
import SimpleCloudinaryImage from '../../common/SimpleCloudinaryImage';

3. Bulk Uploading Images

I used Cloudinary’s API and dashboard to keep the structure:

/images/project/image.jpg → blacro-portfolio/project/image

TIP: Upload everything by folder, so paths never change and the code doesn’t break.


Challenges and How I Solved Them

SSR + Environment Variables

The CldImage component gave errors at build because it tried to access server-only environment variables. Solution: I always render from the client using direct URLs.

priority vs loading in Next.js

If you set priority={true} and loading="lazy" together, Next.js throws an error. Solved it with:

loading={priority ? undefined : loading}

Bulletproof Fallbacks

If Cloudinary fails, the local image should always show. I implemented automatic fallback:

onError={() => {
  console.error('Image failed to load:', imageSrc);
  setImageError(true);
}}

The Numbers Don’t Lie

After the migration:


Best Practices I Implemented


Is Migration Worth It?

If you’re still loading local images, you’ll regret it sooner or later. Migration takes one day and you see instant benefits. Less bandwidth, fewer build issues, more speed, and your site feels way more pro.


My Recommendations:

  1. Plan your image structure before uploading anything.
  2. Implement fallbacks so UX never breaks if Cloudinary doesn’t respond.
  3. Centralize image handling in a single component.
  4. Always monitor performance after every change.
  5. Never upload local images to the repo again. Seriously.

Thinking about scaling your site or just want better performance? Migrating to Cloudinary or any image CDN should be on your checklist.
No way I’m ever going back.


Migration done with Next.js 15, Cloudinary, and a performance obsession.