Skip to content

Photos from Cloudinary

Out of the box, your template resizes every photo when the site is built and serves AVIF and WebP versions from your own host. That is fast and needs no account. With Cloudinary turned on, the photos are delivered by Cloudinary’s image CDN instead: resized on request, in the best format each browser takes, and cached close to your visitors.

Templates: all (a site made earlier gets it with npx wptom update). Service: Cloudinary (free plan available; usage above it is paid, see Cloudinary’s pricing). Setting: PUBLIC_CLOUDINARY_CLOUD_NAME.

  • Production builds only. Cloudinary is used when the site is built for production (npm run build, and every deploy). npm run dev keeps serving the photos itself, because Cloudinary can’t reach your computer.

  • Fetch URLs. You don’t upload anything. Each photo’s address points at Cloudinary, which fetches the original from your live site once, keeps it, and serves the resized copies:

    https://res.cloudinary.com/<cloud-name>/image/fetch/c_limit,w_960,f_auto,q_auto/https://your-domain.com/_astro/photo.jpg
  • f_auto and q_auto. Cloudinary picks the format (AVIF or WebP where the browser supports them) and a quality that keeps the photo looking the same at a smaller size. c_limit never makes a photo larger than its original.

  • A srcset. Each photo lists the same widths as before, so phones download small copies and large screens sharp ones.

  • Which photos. The site’s own photos (the files in your project, also when edited in Keystatic). Photos that come from a hosted CMS (Sanity, EmDash) are served the way they were before. Icons, the logo and drawn graphics are unchanged.

Your site’s address in astro.config.mjs (site) is where Cloudinary fetches the originals from, so it must be your live domain.

Nothing changes: photos are resized at build time and served from your host, as AVIF and WebP with a JPEG fallback.

  1. Sign up at cloudinary.com (or sign in).
  2. On the Console’s home page (Dashboard, under your product environment), copy the Cloud name, e.g. dxyz123ab. It is not your account email or the environment’s display name.

2. Allow fetched URLs, for your domain only

Section titled “2. Allow fetched URLs, for your domain only”

New Cloudinary accounts block fetch URLs until you allow them.

  1. In the Console, open Settings → Security.
  2. Under Restricted media types, uncheck Fetched URL, so fetched images are allowed.
  3. Under Allowed fetch domains, add your site’s domain (e.g. your-domain.com, and www.your-domain.com if you use it). Then Cloudinary fetches only from your site, and nobody can use your account to deliver other people’s images.
  4. Save.

In .env and in Vercel (Settings → Environment Variables):

Terminal window
PUBLIC_CLOUDINARY_CLOUD_NAME=dxyz123ab

Then redeploy. The setting is written into the pages at build time, so it takes effect only in a new build.

Locally, npm run dev doesn’t change. A local npm run build with the setting already points the photos at Cloudinary, which fetches them from your live site: if that site doesn’t have the same photos yet, the preview shows broken images. Test on the deployed site instead.

  1. Open the live site, right-click a photo and choose Inspect. Its src and srcset start with https://res.cloudinary.com/<your-cloud-name>/image/fetch/.
  2. In the developer tools’ Network tab (filter Img), reload: the photos come from res.cloudinary.com, with the type avif or webp.
  3. The first visit to each photo is a little slower while Cloudinary fetches the original; the next ones are served from its cache.
  4. In the Cloudinary Console, the usage reports show the delivered images and transformations.

Remove PUBLIC_CLOUDINARY_CLOUD_NAME in Vercel (and .env) and redeploy. The photos are resized at build time again, as before.

  • No setting, or npm run dev: the photos are served by your site, as without Cloudinary.
  • A cloud name with characters Cloudinary doesn’t allow (spaces, dots…): Cloudinary is switched off for the build, the build log shows [photo] Cloudinary is off: Invalid Cloudinary cloud name, and the photos are served by your site. Your site never fails to build because of it.
  • A cloud name that looks right but isn’t yours, or fetched URLs still blocked: the build can’t tell, and the photos break on the live site. See below.
What you see Why, and what to do
Photos are broken on the live site; opening one shows an error from Cloudinary Fetched URLs are still restricted, or your domain isn’t in Allowed fetch domains (check www too). Fix it in Settings → Security; no redeploy needed
Broken photos, and the Cloudinary address contains another domain The site in astro.config.mjs isn’t your live domain. Set it and redeploy
Broken photos right after the first deploy with Cloudinary Check the cloud name: copy it again from the Console. A wrong cloud name gives Cloudinary errors for every photo
Photos still come from your own domain The setting wasn’t there when the site was built: add it in Vercel and redeploy. Or the photo comes from Sanity or EmDash, which keep their own delivery
[photo] Cloudinary is off in the build log The cloud name has the wrong form. Copy it again, without spaces or quotes
You replaced a photo, but the old one still shows Cloudinary keeps fetched originals for a while. A new file name (which a build gives a changed photo) is fetched fresh