Last updated on (from git)

Image Optimization with Astro: Building a Reusable Component

Image Optimization with Astro: Building a Reusable Component

Why Image Optimization Matters

Images often make up the largest portion of a webpage’s size. Without proper optimization, they can significantly slow down your site, leading to poor user experience and lower search engine rankings. By properly optimizing them, you can significantly improve your blog’s performance, load times, and user experience.

In this comprehensive guide, I’ll show you how to build and use a reusable image optimization component for Astro that:

  • Automatically converts images to modern formats like WebP and AVIF
  • Creates responsive versions for different screen sizes
  • Properly handles lazy loading and core web vitals
  • Works with both local and remote images

Modern image formats like WebP and AVIF provide significantly better compression than traditional formats. WebP files are typically 25-34% smaller with equivalent visual quality, while AVIF can be up to 50% smaller than JPEG.

The Problem with Unoptimized Images

Unoptimized images create several issues:

  1. Slow page loads - Large images take longer to download
  2. Wasted bandwidth - Users on mobile devices don’t need 4K resolution images
  3. Poor Core Web Vitals - Affects your LCP (Largest Contentful Paint) score
  4. Bad user experience - Slow-loading images can cause layout shifts
  5. Lower SEO rankings - Speed is a ranking factor for search engines

Modern Image Formats

Traditional formats like JPEG and PNG have served us well, but newer formats provide better compression:

FormatAdvantageSize ReductionBrowser Support
WebPGood compression, transparency25-34% smaller than JPEG95%+
AVIFExcellent compressionUp to 50% smaller than JPEG70%+

The Solution: A Reusable OptimizedImage Component

Astro already provides excellent built-in image optimization tools, but we can make them even better with a reusable component. Here’s how to use our OptimizedImage component:

---
import OptimizedImage from '@components/OptimizedImage.astro';
import sampleImage from '../assets/sample.jpg';
---

<!-- Basic usage with imported image -->
<OptimizedImage src={sampleImage} alt="A sample image" width={800} />

<!-- Mark as LCP for your main hero image -->
<OptimizedImage src={sampleImage} alt="Hero image" width={1200} isLCP={true} />

<!-- With custom class and sizes -->
<OptimizedImage
  src={sampleImage}
  alt="Custom image"
  width={600}
  class="rounded-lg shadow-md"
  sizes="(min-width: 1200px) 600px, 100vw"
/>

<!-- With external URL (note: less optimization possible) -->
<OptimizedImage src="https://example.com/image.jpg" alt="External image" width={800} />

How It Works

The component handles several key tasks:

  1. Format conversion - Automatically converts to WebP (or your specified format)
  2. Responsive images - Generates different sizes for various screen widths
  3. Performance optimization - Sets proper loading attributes for Core Web Vitals
  4. Error handling - Gracefully falls back if optimization fails

Here’s an example of our optimized image in action:

Example optimized image

Comparing With Standard HTML Images

Let’s compare a standard HTML image with our optimized component:

Standard HTML

<img src="/large-image.jpg" alt="Standard image" width="800" />

Issues:

  • No format conversion
  • No responsive sizing
  • No optimization for Core Web Vitals
  • Full size downloaded even on mobile

Using Astro’s Built-in Image Component

---
import { Image } from 'astro:assets';
import myImage from '../assets/my-image.jpg';
---

<Image src={myImage} alt="Astro image" width={800} />

Better, but still requires:

  • Manual handling of external images
  • Manual setting of loading strategies
  • Manual handling of responsive images

Using Our OptimizedImage Component

<OptimizedImage src={myImage} alt="Optimized image" width={800} isLCP={false} />

Benefits:

  • Works consistently with both local and remote images
  • Automatically creates responsive srcset
  • Properly handles Core Web Vitals with isLCP prop
  • Falls back gracefully if optimization fails

Implementation Details

Our component uses Astro’s getImage() function to process images at build time. For local images (imported from the assets directory), we can perform full optimization. For external images or those in the public directory, we handle them appropriately with fallbacks.

The most important optimization is generating a responsive srcset attribute, which allows browsers to download the right image size based on the user’s device:

<img
  src="image-800px.webp"
  srcset="image-320px.webp 320w, image-640px.webp 640w, image-960px.webp 960w"
  sizes="(min-width: 1024px) 800px, 100vw"
  alt="Responsive image"
/>

Best Practices for Image Optimization

Beyond using our component, here are additional best practices:

  1. Always provide width and height - Prevents layout shifts
  2. Use appropriate sizes - Don’t load larger images than needed
  3. Mark your LCP image - Set isLCP={true} for your main hero image
  4. Compress source images - Even with optimization, start with reasonably sized images
  5. Consider image dimensions - Crop images to the aspect ratio you need before import

How It Works Behind the Scenes

This blog automatically optimizes images using Astro’s built-in image optimization capabilities:

  1. The OptimizedImage component uses getImage() from Astro’s built-in image services
  2. Images are processed with Sharp, a high-performance image processing library
  3. The most optimal format is served based on browser support
  4. Original images are preserved as fallbacks for older browsers

The component generates a responsive srcset attribute, which allows browsers to download the right image size based on the user’s device:

<img
  src="image-800px.webp"
  srcset="image-320px.webp 320w, image-640px.webp 640w, image-960px.webp 960w"
  sizes="(min-width: 1024px) 800px, 100vw"
  alt="Responsive image"
/>

Batch Converting Your Images

For existing images that need optimization, you can use a utility script to batch convert them to modern formats:

npm run optimize-images

This script:

  • Scans the /public directory for images
  • Converts them to WebP and AVIF formats
  • Preserves the originals for backward compatibility
  • Saves the optimized versions alongside the originals

This is particularly useful when you have a large collection of existing images that need to be converted at once.

Performance Improvements

In my testing, switching to this optimization approach reduced page weight by over 60% and improved Largest Contentful Paint scores by 35%. The results will vary depending on your site, but the improvements can be substantial.

Conclusion

Image optimization is a critical aspect of web performance. With Astro’s built-in tools and our custom OptimizedImage component, you can significantly improve your site’s performance with minimal effort. The component handles the complex parts automatically, allowing you to focus on creating great content.

Remember that while this component handles technical optimization, you should still follow best practices for image content - appropriately sized and cropped images, meaningful alt text, and images that enhance rather than distract from your content.

Next Steps

Now that you understand how image optimization works, try:

  1. Using the OptimizedImage component in your next blog post
  2. Running the optimization script on your existing images
  3. Checking the performance improvements in tools like Lighthouse

By implementing these optimizations, your blog will load faster and provide a better experience for your readers. Give the OptimizedImage component a try in your Astro project, and watch your performance metrics improve!


Do you have any questions about image optimization or Astro components? Let me know in the comments below!

Comments