{"id":40049,"date":"2026-05-19T07:00:00","date_gmt":"2026-05-19T14:00:00","guid":{"rendered":"https:\/\/cloudinary.com\/blog\/?p=40049"},"modified":"2026-05-20T14:49:25","modified_gmt":"2026-05-20T21:49:25","slug":"astro-portfolio-cloudinary-image-optimization","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization","title":{"rendered":"Build a Fast Astro Portfolio With Cloudinary Image Optimization"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>A fast Astro portfolio helps showcase your work without sacrificing page performance. In this tutorial, you\u2019ll learn how to build a high-performance <a href=\"https:\/\/cloudinary.com\/blog\/astro-cloudinary-image-video-api\">Astro<\/a> site using Cloudinary\u2019s automated image delivery to deliver responsive images that load quickly across devices.<\/p>\n<ul>\n<li>\n<strong>Live Demo:<\/strong> <a href=\"https:\/\/my-portfolio-navy-two-o6ync5ksvm.vercel.app\/\">https:\/\/my-portfolio-navy-two-o6ync5ksvm.vercel.app\/<\/a>\n<\/li>\n<li>\n<strong>GitHub Repo:<\/strong> <a href=\"https:\/\/github.com\/musebe\/my-portfolio\">https:\/\/github.com\/musebe\/my-portfolio<\/a>\n<\/li>\n<\/ul>\n<h2>The Problem: \u2018Image Tax\u2019<\/h2>\n<p>Images are essential, but when left unoptimized, they can cause slow load times, tanking your <strong>Core Web Vitals<\/strong>, search rankings, and customer experience.<\/p>\n<p>Typical bottlenecks include:<\/p>\n<ul>\n<li>Serving raw, high-res JPEGs where a thumbnail would suffice.<\/li>\n<li>Content \u201cjumping\u201d because width and height attributes are missing.<\/li>\n<li>Sending the same desktop-sized file to a smartphone.<\/li>\n<\/ul>\n<h2>The Solution: URL-Based Optimization<\/h2>\n<p>With <a href=\"https:\/\/cloudinary.com\/documentation\/image_transformations\">Cloudinary\u2019s dynamic image transformations<\/a>, you can automate tedious, manual editing tasks like resizing, compressing, or exporting multiple versions of the same file just by tweaking the image\u2019s URL.<\/p>\n<p>For this portfolio, you\u2019ll focus on three core optimizations:<\/p>\n<ul>\n<li>\n<strong><code>f_auto<\/code>.<\/strong> Automatically serve the most efficient format (like AVIF or WebP) based on the user\u2019s browser.<\/li>\n<li>\n<strong><code>q_auto<\/code>.<\/strong> Compress the image to the smallest possible weight without visible loss in quality.<\/li>\n<li>\n<strong>Responsive sizing (<code>w_<\/code>).<\/strong> Scale the image to the exact pixels required for the visitor\u2019s screen.<\/li>\n<\/ul>\n<p>Here\u2019s how the image optimizations work:<\/p>\n<p>Let\u2019s take a look at a processed Cloudinary URL.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">https:<span class=\"hljs-comment\">\/\/res.cloudinary.com\/cloud-name\/image\/upload\/f_auto,q_auto,w_800\/image-id<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Everything following the <code>\/upload\/<\/code> directory tells Cloudinary how to transform the file. This ensures your portfolio stays professional without impacting performance.<\/p>\n<h2>Project Setup<\/h2>\n<p>Start by creating a new Astro project.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">npm<\/span> <span class=\"hljs-selector-tag\">create<\/span> <span class=\"hljs-selector-tag\">astro<\/span><span class=\"hljs-keyword\">@latest<\/span> my-portfolio\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Move into the project folder:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">cd my-portfolio\n<\/code><\/span><\/pre>\n<p>Then install the project dependencies:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">npm install\n<\/code><\/span><\/pre>\n<p>Astro gives you a clean setup for building fast static sites. For this portfolio, you\u2019ll use Cloudinary through image URLs. <strong>You do not need an extra Cloudinary package for the basic image setup.<\/strong><\/p>\n<p>Next, create a <code>.env<\/code> file in the project root:<\/p>\n<pre class=\"js-syntax-highlighted\"><code>PUBLIC_CLOUDINARY_CLOUD_NAME=your_cloud_name\n<\/code><\/pre>\n<p>Replace <code>your_cloud_name<\/code> with your Cloudinary cloud name. The <code>PUBLIC_<\/code> prefix makes the value available to Astro when it builds the site.<\/p>\n<h2>Create a Cloudinary URL Helper<\/h2>\n<p>To keep your image logic DRY (Don\u2019t Repeat Yourself), create a utility file to manage your image transformations. This ensures every image across your portfolio follows the same <a href=\"https:\/\/cloudinary.com\/documentation\/resizing_and_cropping\">optimization rules<\/a>.<\/p>\n<p>Create <code>src\/lib\/cloudinary.ts<\/code> and add the following:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> CLOUD_NAME = <span class=\"hljs-keyword\">import<\/span>.meta.env.PUBLIC_CLOUDINARY_CLOUD_NAME;\n<span class=\"hljs-keyword\">const<\/span> BASE_URL = <span class=\"hljs-string\">`https:\/\/res.cloudinary.com\/<span class=\"hljs-subst\">${CLOUD_NAME}<\/span>\/image\/upload`<\/span>;\n\ntype ImageOptions = {\n  width?: number;\n  height?: number;\n  crop?: <span class=\"hljs-string\">\"fill\"<\/span> | <span class=\"hljs-string\">\"fit\"<\/span> | <span class=\"hljs-string\">\"scale\"<\/span>;\n  gravity?: <span class=\"hljs-string\">\"auto\"<\/span> | <span class=\"hljs-string\">\"center\"<\/span>;\n};\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">buildTransformations<\/span>(<span class=\"hljs-params\">options: ImageOptions = {}<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> transformations = &#91;<span class=\"hljs-string\">\"f_auto\"<\/span>, <span class=\"hljs-string\">\"q_auto\"<\/span>];\n\n  <span class=\"hljs-keyword\">if<\/span> (options.width) transformations.push(<span class=\"hljs-string\">`w_<span class=\"hljs-subst\">${options.width}<\/span>`<\/span>);\n  <span class=\"hljs-keyword\">if<\/span> (options.height) transformations.push(<span class=\"hljs-string\">`h_<span class=\"hljs-subst\">${options.height}<\/span>`<\/span>);\n  <span class=\"hljs-keyword\">if<\/span> (options.crop) transformations.push(<span class=\"hljs-string\">`c_<span class=\"hljs-subst\">${options.crop}<\/span>`<\/span>);\n  <span class=\"hljs-keyword\">if<\/span> (options.gravity) transformations.push(<span class=\"hljs-string\">`g_<span class=\"hljs-subst\">${options.gravity}<\/span>`<\/span>);\n\n  <span class=\"hljs-keyword\">return<\/span> transformations.join(<span class=\"hljs-string\">\",\"<\/span>);\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">getImageUrl<\/span>(<span class=\"hljs-params\">publicId: string, options: ImageOptions = {}<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> transformations = buildTransformations(options);\n\n  <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-string\">`<span class=\"hljs-subst\">${BASE_URL}<\/span>\/<span class=\"hljs-subst\">${transformations}<\/span>\/<span class=\"hljs-subst\">${publicId}<\/span>`<\/span>;\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Here\u2019s why this works:<\/p>\n<ul>\n<li>\n<code>CLOUD_NAME<\/code> is pulled from your <code>.env<\/code> file, keeping your credentials secure and easy to update.<\/li>\n<li>Every URL generated automatically includes <code>f_auto<\/code> and <code>q_auto<\/code>, so you\u2019ll never have to remember to optimize for format or quality manually.<\/li>\n<li>Using a TypeScript <code>type<\/code> for <code>ImageOptions<\/code> gives you autocomplete in your editor, preventing typos in transformation names like <code>fill<\/code> or <code>gravity<\/code>.<\/li>\n<\/ul>\n<p>You can now generate a perfectly cropped hero image with a simple function call:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> heroUrl = getImageUrl(<span class=\"hljs-string\">\"portfolio\/project-one\"<\/span>, {\n  <span class=\"hljs-attr\">width<\/span>: <span class=\"hljs-number\">800<\/span>,\n  <span class=\"hljs-attr\">height<\/span>: <span class=\"hljs-number\">500<\/span>,\n  <span class=\"hljs-attr\">crop<\/span>: <span class=\"hljs-string\">\"fill\"<\/span>,\n  <span class=\"hljs-attr\">gravity<\/span>: <span class=\"hljs-string\">\"auto\"<\/span>,\n});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This returns an optimized Cloudinary URL for that image. The main benefit is control. You can change your image rules in one file, and the whole portfolio will follow the same pattern.<\/p>\n<h2>Build the Reusable Cloudinary Image Component<\/h2>\n<p>Now that the URL helper is ready, it\u2019s time to create a reusable Astro component for your images.<\/p>\n<p>Create this file:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">src\/components\/CloudinaryImage.astro\n<\/code><\/span><\/pre>\n<p>Add this code:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">---\nimport { getImageUrl } from \"..\/lib\/cloudinary\";\n\ntype Props = {\n  publicId: string;\n  alt: string;\n  width: number;\n  height: number;\n  class?: string;\n};\n\nconst { publicId, alt, width, height, class: className } = Astro.props;\n\nconst src = getImageUrl(publicId, {\n  width,\n  height,\n  crop: \"fill\",\n  gravity: \"auto\",\n});\n---\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span>\n  <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{src}<\/span>\n  <span class=\"hljs-attr\">alt<\/span>=<span class=\"hljs-string\">{alt}<\/span>\n  <span class=\"hljs-attr\">width<\/span>=<span class=\"hljs-string\">{width}<\/span>\n  <span class=\"hljs-attr\">height<\/span>=<span class=\"hljs-string\">{height}<\/span>\n  <span class=\"hljs-attr\">loading<\/span>=<span class=\"hljs-string\">\"lazy\"<\/span>\n  <span class=\"hljs-attr\">decoding<\/span>=<span class=\"hljs-string\">\"async\"<\/span>\n  <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">{className}<\/span>\n\/&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This component simplifies reusing your images. Instead of writing a full Cloudinary URL each time, you just have to pass a <code>publicId<\/code>, <code>alt<\/code>, <code>width<\/code>, and <code>height<\/code>.<\/p>\n<p>These attributes help with:<\/p>\n<ul>\n<li>\n<code>alt<\/code>: Screen readers and SEO.<\/li>\n<li>\n<code>width<\/code> and <code>height<\/code>: Prevents layout shifts.<\/li>\n<li>\n<code>loading=&quot;lazy&quot;<\/code>: Delays images until needed.<\/li>\n<li>\n<code>decoding=&quot;async&quot;<\/code>: Faster rendering of the page.<\/li>\n<\/ul>\n<p>Now you can use the component like this:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">CloudinaryImage<\/span>\n  <span class=\"hljs-attr\">publicId<\/span>=<span class=\"hljs-string\">\"portfolio\/project-one\"<\/span>\n  <span class=\"hljs-attr\">alt<\/span>=<span class=\"hljs-string\">\"Screenshot of my portfolio project\"<\/span>\n  <span class=\"hljs-attr\">width<\/span>=<span class=\"hljs-string\">{800}<\/span>\n  <span class=\"hljs-attr\">height<\/span>=<span class=\"hljs-string\">{500}<\/span>\n\/&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This keeps every portfolio image cleaner, faster, and easier to manage.<\/p>\n<h2>Use Responsive Images in the Portfolio<\/h2>\n<p>The next step is making images work well on different screen sizes. A desktop screen may need a large image, while a mobile phone should get a smaller one.<\/p>\n<p>That is where <code>srcset<\/code> helps. Instead of sending the same image size to every device, <a href=\"https:\/\/cloudinary.com\/documentation\/responsive_images\"><code>srcset<\/code><\/a> gives the browser a list of image sizes to choose from.<\/p>\n<p>You can update the helper with a <code>getSrcSet<\/code> function:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">getSrcSet<\/span>(<span class=\"hljs-params\">\n  publicId: string,\n  widths: number&#91;] = &#91;<span class=\"hljs-number\">400<\/span>, <span class=\"hljs-number\">800<\/span>, <span class=\"hljs-number\">1200<\/span>, <span class=\"hljs-number\">1600<\/span>],\n  options: Omit&lt;ImageOptions, <span class=\"hljs-string\">\"width\"<\/span>&gt; = {}\n<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> widths\n    .map(<span class=\"hljs-function\">(<span class=\"hljs-params\">width<\/span>) =&gt;<\/span> {\n      <span class=\"hljs-keyword\">const<\/span> url = getImageUrl(publicId, { ...options, width });\n      <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-string\">`<span class=\"hljs-subst\">${url}<\/span> <span class=\"hljs-subst\">${width}<\/span>w`<\/span>;\n    })\n    .join(<span class=\"hljs-string\">\", \"<\/span>);\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This creates several <a href=\"https:\/\/cloudinary.com\/documentation\/responsive_html\">Cloudinary URLs for the same image<\/a>. Each URL has a different width.<\/p>\n<p>For example:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">image-400w\nimage-800w\nimage-1200w\nimage-1600w\n<\/code><\/span><\/pre>\n<p>The browser checks the user\u2019s screen and picks the best size, reducing wasted bandwidth on mobile devices and ensuring a faster portfolio.<\/p>\n<h2>Prevent Layout Shift With Width and Height<\/h2>\n<p>Images shouldn\u2019t push content around as they load on the screen (aka <a href=\"https:\/\/web.dev\/articles\/cls\">layout shift<\/a>). It can make a page feel unstable, especially on mobile.<\/p>\n<p>To avoid this, every image should include a clear <code>width<\/code> and <code>height<\/code>.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">CloudinaryImage<\/span>\n  <span class=\"hljs-attr\">publicId<\/span>=<span class=\"hljs-string\">\"portfolio\/project-one\"<\/span>\n  <span class=\"hljs-attr\">alt<\/span>=<span class=\"hljs-string\">\"Screenshot of a portfolio project\"<\/span>\n  <span class=\"hljs-attr\">width<\/span>=<span class=\"hljs-string\">{800}<\/span>\n  <span class=\"hljs-attr\">height<\/span>=<span class=\"hljs-string\">{500}<\/span>\n\/&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>These values help the browser reserve space before the image appears. That means your layout stays steady while Cloudinary loads the optimized image.<\/p>\n<p>This also supports accessibility. The <code>alt<\/code> text gives screen readers a clear description of the image. The fixed image size helps users avoid sudden page movement while reading or scrolling.<\/p>\n<p>For a portfolio, both are essential because your work should feel easy to view from the first load.<\/p>\n<h2>Add a Fast Hero Image<\/h2>\n<p>A portfolio homepage often starts with a hero section.This is usually the first image users see, so it needs to load fast and look good. For this project, we use the same Cloudinary image in two ways:<\/p>\n<ul>\n<li>A sharp image for the main visual<\/li>\n<li>A blurred version for the background<\/li>\n<\/ul>\n<p>The blurred version can be created with a Cloudinary transformation:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> blurredBg = getImageUrl(<span class=\"hljs-string\">\"portfolio\/hero-image\"<\/span>, {\n  <span class=\"hljs-attr\">width<\/span>: <span class=\"hljs-number\">1440<\/span>,\n  <span class=\"hljs-attr\">height<\/span>: <span class=\"hljs-number\">760<\/span>,\n  <span class=\"hljs-attr\">crop<\/span>: <span class=\"hljs-string\">\"fill\"<\/span>,\n  <span class=\"hljs-attr\">gravity<\/span>: <span class=\"hljs-string\">\"auto\"<\/span>,\n  <span class=\"hljs-attr\">blur<\/span>: <span class=\"hljs-number\">2000<\/span>,\n});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>The sharp image can use the same public ID, without the blur:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">CloudinaryImage<\/span>\n  <span class=\"hljs-attr\">publicId<\/span>=<span class=\"hljs-string\">\"portfolio\/hero-image\"<\/span>\n  <span class=\"hljs-attr\">alt<\/span>=<span class=\"hljs-string\">\"Portfolio project preview\"<\/span>\n  <span class=\"hljs-attr\">width<\/span>=<span class=\"hljs-string\">{880}<\/span>\n  <span class=\"hljs-attr\">height<\/span>=<span class=\"hljs-string\">{495}<\/span>\n  <span class=\"hljs-attr\">loading<\/span>=<span class=\"hljs-string\">\"eager\"<\/span>\n\/&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>The idea is simple. Cloudinary creates two versions from one image. You don\u2019t need to edit or export extra files.<\/p>\n<p>Use <code>loading=&quot;eager&quot;<\/code> only for the hero image because it appears first on the page. Other images should stay lazy-loaded.<\/p>\n<h2>Generate Open Graph Images With Cloudinary<\/h2>\n<p>Open Graph images control how your portfolio links look when shared on social platforms.<\/p>\n<p>Instead of creating a separate social image by hand, you can <a href=\"https:\/\/cloudinary.com\/blog\/dynamic-open-graph-images-astro\">generate one with Cloudinary<\/a>.<\/p>\n<p>Add a helper function like this:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">getOgImageUrl<\/span>(<span class=\"hljs-params\">publicId: string<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-string\">`<span class=\"hljs-subst\">${BASE_URL}<\/span>\/c_fill,w_1200,h_630,g_auto\/e_brightness:-15,f_auto,q_auto\/<span class=\"hljs-subst\">${publicId}<\/span>`<\/span>;\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This creates a <code>1200x630<\/code> image, which is a common size for social previews.<\/p>\n<p>Here\u2019s what the transformation does:<\/p>\n<ul>\n<li>\n<code>c_fill,w_1200,h_630<\/code> crops the image to the right size.<\/li>\n<li>\n<code>g_auto<\/code> helps keep the main subject in view.<\/li>\n<li>\n<code>e_brightness:-15<\/code> darkens the image slightly.<\/li>\n<li>\n<code>f_auto,q_auto<\/code> keeps the image optimized.<\/li>\n<\/ul>\n<p>You can then use the generated URL in your Astro layout:<\/p>\n<pre class=\"js-syntax-highlighted\"><code>&lt;meta property=&quot;og:image&quot; content={ogImage} \/&gt;\n&lt;meta name=&quot;twitter:card&quot; content=&quot;summary_large_image&quot; \/&gt;\n&lt;meta name=&quot;twitter:image&quot; content={ogImage} \/&gt;\n<\/code><\/pre>\n<p>Now each portfolio page can have a clean social preview image from the same Cloudinary asset. No extra design file or manual export needed!<\/p>\n<h2>Test the Final Portfolio<\/h2>\n<p>Open the live demo:<\/p>\n<pre class=\"js-syntax-highlighted\"><code>https:\/\/my-portfolio-navy-two-o6ync5ksvm.vercel.app\/\n<\/code><\/pre>\n<p>Then check a few things:<\/p>\n<ul>\n<li>Do the images load quickly?<\/li>\n<li>Do they keep their layout space?<\/li>\n<li>Do they look clear on mobile?<\/li>\n<li>Do project images resize well on smaller screens?<\/li>\n<li>Do shared links show the right preview image?<\/li>\n<\/ul>\n<p>You can also inspect an image URL in the browser. You should see Cloudinary transformations like:<\/p>\n<pre class=\"js-syntax-highlighted\"><code>f_auto,q_auto,w_800\n<\/code><\/pre>\n<p>That means the image is being optimized through Cloudinary before it reaches the user. This confirms the main setup is working. Astro renders the portfolio, and Cloudinary prepares the images for faster delivery.<\/p>\n<h2>Best Practices Recap<\/h2>\n<p>Before you wrap up, here are the key rules from this build.<\/p>\n<ul>\n<li>Always use <code>f_auto<\/code> and <code>q_auto<\/code> together.<\/li>\n<li>Store Cloudinary public IDs, not full URLs.<\/li>\n<li>Add <code>width<\/code> and <code>height<\/code> to every image.<\/li>\n<li>Write clear alt text for every image.<\/li>\n<li>Use <code>loading=&quot;eager&quot;<\/code> only for hero images.<\/li>\n<li>Lazy-load images below the first screen.<\/li>\n<li>Use <code>srcset<\/code> so the browser can pick the right size.<\/li>\n<li>Keep Cloudinary URL logic in one helper file.<\/li>\n<li>Reuse one Astro image component across the site.<\/li>\n<\/ul>\n<p>This setup keeps the portfolio easier to maintain.<\/p>\n<p>When you add more projects later, you won\u2019t have to rethink image performance. You can pass a public ID into the component, and Cloudinary will handle the image format, quality, and size.<\/p>\n<h2>Start Building Portfolios With Astro + Cloudinary<\/h2>\n<p>Image performance matters on portfolio sites. Your work may look great, but large images can slow the page down and hurt the users\u2019 experience.<\/p>\n<p>In this build, you used Astro and Cloudinary for a cleaner image setup. You created a Cloudinary URL helper, a reusable image component, responsive image sizes, fixed dimensions, and Open Graph images. The result is a portfolio that loads faster, keeps the layout stable, and serves better images for each screen.<\/p>\n<p>If you\u2019d like to try Cloudinary for yourself, <a href=\"https:\/\/cloudinary.com\/users\/register_free\">sign up<\/a> for a free account.<\/p>\n<p>You can view the final project here:<\/p>\n<ul>\n<li>\n<strong>Live Demo:<\/strong> <a href=\"https:\/\/my-portfolio-navy-two-o6ync5ksvm.vercel.app\/\">https:\/\/my-portfolio-navy-two-o6ync5ksvm.vercel.app\/<\/a>\n<\/li>\n<li>\n<strong>GitHub Repo:<\/strong> <a href=\"https:\/\/github.com\/musebe\/my-portfolio\">https:\/\/github.com\/musebe\/my-portfolio<\/a>\n<\/li>\n<\/ul>\n<\/div>\n\n\n<style>\n    .faqs {padding: 30px 60px; margin-top: 40px;background: var(--color-background-offset);border-radius: 20px;}\n    #frequently_asked_questions {margin-bottom: 20px;}\n    .question {margin-bottom: 20px;}\n<\/style>\n\n\n<div class=\"faqs\">\n\n<h2>Frequently Asked Questions<\/h2>\n<div class=\"question\">\n<p><b>Why should I use Cloudinary for my Astro portfolio images?<\/b><\/p>\nUsing Cloudinary allows you to offload image processing and delivery, ensuring your site remains fast without the &#8220;image tax&#8221; of unoptimized assets. It automates technical tasks like format conversion, quality compression, and responsive resizing through simple URL transformations, which directly improves Core Web Vitals and user experience.\n<\/div>\n\n<div class=\"question\">\n<p><b>How does the app work with Cloudinary DAM?<\/b><\/p>\nThe app integrates directly with Cloudinary DAM as a custom action. Users can select assets from the Cloudinary Media Library, open them in the Animation Maker, apply transformations, reorder frames, adjust timing, and export the final animation or spritesheet without leaving the DAM environment.\n<\/div>\n\n<div class=\"question\">\n<p><b>WWhat do `f_auto` and `q_auto` do in Cloudinary transformations?<\/b><\/p>\nThese are automatic optimization flags. f_auto (fetch format) identifies the best image format for the visitor&#8217;s browser (like AVIF or WebP), while q_auto (quality) compresses the file to the smallest possible size without any visible loss in quality.\n<\/div>\n\n<div class=\"question\">\n<p><b>How do I prevent Content Layout Shift (CLS) when using remote images in Astro?<\/b><\/p>\nYes. Each animation frame can have its own Cloudinary transformations applied independently. Users can preview transformations directly in the interface before generating the final output.\n<\/div>\n\n<div class=\"question\">\n<p><b>Can I generate social media (Open Graph) images automatically?<\/b><\/p>\nYes. You can create a helper function that uses Cloudinary transformations, such as c_fill,w_1200,h_630, to dynamically generate perfectly sized social preview images from your existing portfolio assets. This eliminates the need for manual design and exports for each page.\n<\/div>\n\n<div class=\"question\">\n<p><b>When should I use loading=&#8221;eager&#8221; versus loading=&#8221;lazy&#8221; for images?<\/b><\/p>\nYou should use loading=&#8221;eager&#8221; only for &#8220;above the fold&#8221; content, such as your hero image, to ensure it appears immediately when the page loads. All other images should use loading=&#8221;lazy&#8221; to delay download until the user scrolls near them, saving bandwidth and improving initial load speed.\n<\/div>\n\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Frequently Asked Questions Why should I use Cloudinary for my Astro portfolio images? Using Cloudinary allows you to offload image processing and delivery, ensuring your site remains fast without the &#8220;image tax&#8221; of unoptimized assets. It automates technical tasks like format conversion, quality compression, and responsive resizing through simple URL transformations, which directly improves Core [&hellip;]<\/p>\n","protected":false},"author":87,"featured_media":40051,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[165,227],"class_list":["post-40049","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-image-transformation","tag-performance-optimization"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Build a Fast Astro Portfolio: Cloudinary Image Optimization Guide<\/title>\n<meta name=\"description\" content=\"Learn how to build a high-performance Astro site using Cloudinary for automated image delivery. Optimize Core Web Vitals with responsive sizing and f_auto\/q_auto transformations.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Build a Fast Astro Portfolio With Cloudinary Image Optimization\" \/>\n<meta property=\"og:description\" content=\"Learn how to build a high-performance Astro site using Cloudinary for automated image delivery. Optimize Core Web Vitals with responsive sizing and f_auto\/q_auto transformations.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-05-19T14:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-05-20T21:49:25+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1778863772\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization.jpg?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"2000\" \/>\n\t<meta property=\"og:image:height\" content=\"1100\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"melindapham\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization\"},\"author\":{\"name\":\"melindapham\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\"},\"headline\":\"Build a Fast Astro Portfolio With Cloudinary Image Optimization\",\"datePublished\":\"2026-05-19T14:00:00+00:00\",\"dateModified\":\"2026-05-20T21:49:25+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization\"},\"wordCount\":322,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1778863772\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization.jpg?_i=AA\",\"keywords\":[\"Image Transformation\",\"Performance Optimization\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2026\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization\",\"url\":\"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization\",\"name\":\"Build a Fast Astro Portfolio: Cloudinary Image Optimization Guide\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1778863772\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization.jpg?_i=AA\",\"datePublished\":\"2026-05-19T14:00:00+00:00\",\"dateModified\":\"2026-05-20T21:49:25+00:00\",\"description\":\"Learn how to build a high-performance Astro site using Cloudinary for automated image delivery. Optimize Core Web Vitals with responsive sizing and f_auto\/q_auto transformations.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1778863772\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1778863772\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization.jpg?_i=AA\",\"width\":2000,\"height\":1100},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Build a Fast Astro Portfolio With Cloudinary Image Optimization\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\",\"name\":\"melindapham\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"caption\":\"melindapham\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Build a Fast Astro Portfolio: Cloudinary Image Optimization Guide","description":"Learn how to build a high-performance Astro site using Cloudinary for automated image delivery. Optimize Core Web Vitals with responsive sizing and f_auto\/q_auto transformations.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization","og_locale":"en_US","og_type":"article","og_title":"Build a Fast Astro Portfolio With Cloudinary Image Optimization","og_description":"Learn how to build a high-performance Astro site using Cloudinary for automated image delivery. Optimize Core Web Vitals with responsive sizing and f_auto\/q_auto transformations.","og_url":"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization","og_site_name":"Cloudinary Blog","article_published_time":"2026-05-19T14:00:00+00:00","article_modified_time":"2026-05-20T21:49:25+00:00","og_image":[{"width":2000,"height":1100,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1778863772\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization.jpg?_i=AA","type":"image\/jpeg"}],"author":"melindapham","twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization"},"author":{"name":"melindapham","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9"},"headline":"Build a Fast Astro Portfolio With Cloudinary Image Optimization","datePublished":"2026-05-19T14:00:00+00:00","dateModified":"2026-05-20T21:49:25+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization"},"wordCount":322,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1778863772\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization.jpg?_i=AA","keywords":["Image Transformation","Performance Optimization"],"inLanguage":"en-US","copyrightYear":"2026","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization","url":"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization","name":"Build a Fast Astro Portfolio: Cloudinary Image Optimization Guide","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1778863772\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization.jpg?_i=AA","datePublished":"2026-05-19T14:00:00+00:00","dateModified":"2026-05-20T21:49:25+00:00","description":"Learn how to build a high-performance Astro site using Cloudinary for automated image delivery. Optimize Core Web Vitals with responsive sizing and f_auto\/q_auto transformations.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1778863772\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1778863772\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization.jpg?_i=AA","width":2000,"height":1100},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Build a Fast Astro Portfolio With Cloudinary Image Optimization"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9","name":"melindapham","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","caption":"melindapham"}}]}},"parsely":{"version":"1.1.0","canonical_url":"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization","smart_links":{"inbound":0,"outbound":0},"traffic_boost_suggestions_count":0,"meta":{"@context":"https:\/\/schema.org","@type":"NewsArticle","headline":"Build a Fast Astro Portfolio With Cloudinary Image Optimization","url":"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization","mainEntityOfPage":{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1778863772\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization.jpg?_i=AA&w=150&h=150&crop=1","image":{"@type":"ImageObject","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1778863772\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization.jpg?_i=AA"},"articleSection":"Uncategorized","author":[{"@type":"Person","name":"melindapham"}],"creator":["melindapham"],"publisher":{"@type":"Organization","name":"Cloudinary Blog","logo":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA"},"keywords":["image transformation","performance optimization"],"dateCreated":"2026-05-19T14:00:00Z","datePublished":"2026-05-19T14:00:00Z","dateModified":"2026-05-20T21:49:25Z"},"rendered":"<meta name=\"parsely-title\" content=\"Build a Fast Astro Portfolio With Cloudinary Image Optimization\" \/>\n<meta name=\"parsely-link\" content=\"https:\/\/cloudinary.com\/blog\/astro-portfolio-cloudinary-image-optimization\" \/>\n<meta name=\"parsely-type\" content=\"post\" \/>\n<meta name=\"parsely-image-url\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1778863772\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization.jpg?_i=AA&w=150&amp;h=150&amp;crop=1\" \/>\n<meta name=\"parsely-pub-date\" content=\"2026-05-19T14:00:00Z\" \/>\n<meta name=\"parsely-section\" content=\"Uncategorized\" \/>\n<meta name=\"parsely-tags\" content=\"image transformation,performance optimization\" \/>\n<meta name=\"parsely-author\" content=\"melindapham\" \/>","tracker_url":"https:\/\/cdn.parsely.com\/keys\/cloudinary.com\/p.js"},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1778863772\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization\/Blog_Build_a_Fast_Astro_Portfolio_with_Cloudinary_Image_Optimization.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/40049","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/87"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=40049"}],"version-history":[{"count":4,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/40049\/revisions"}],"predecessor-version":[{"id":40059,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/40049\/revisions\/40059"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/40051"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=40049"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=40049"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=40049"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}