Overview

Images are usually the heaviest components of a web page, both in terms of bytes and number of HTTP requests. Optimizing images on your website is critical to improve your users’ experience, reduce delivery costs and enhance your position in search engine ranking. For example, Google’s Largest Contentful Paint metric in their search ranking algorithm is highly impacted by how much you optimize the images on your website.

Architectural decisions

An image optimization solution can be architected in a variety of ways, based on your requirements in terms of cost, flexibility, and performance. When architecting an image optimization solution, you need to make the following technical decisions:

  • What image transformations are needed? Is it formatting, resizing, cropping, etc.
  • Where do we decide which transformation to be applied for a specific image request? In the front-end on the client-side (static, responsive design, etc.), on the server side (based on request content such as device) or combination of both?
  • Where do we execute the transformation? In a central location or in a distributed way?
  • When do we execute the transformation? Every time or do we store transformed images for a short duration? Is it synchronously or asynchronously executed?

Another important decision to make is whether you want to build the solution using AWS services, or buy a 3rd party managed solution.

Common use cases

Customer managed solution based on CloudFront, S3 & Lambda

The most common use case for image optimization requires automatic formatting based on user browser capabilities, and giving the front-end the possibility to resize the image. Popular web development frameworks such as Next.JS provide responsive image components that can select automatically the image size based on the device viewport. The recommended architecture for this common use case is explained in the following diagram:

  1. The user sends an HTTP request for an image with specific transformations, such as encoding and size. The transformations are encoded in the URL, more precisely as query parameters. An example URL would look like this: https://exmaples.com/images/cats/mycat.jpg?format=webp&width=200.
  2. The request is processed by a nearby CloudFront edge location providing the best performance. Before passing the request upstream, a CloudFront Function is executed on viewer request event to rewrite the request URL. CloudFront Functions is a feature of CloudFront that allows you to write lightweight functions in JavaScript for high-scale, latency-sensitive CDN customizations. In our architecture, we rewrite the URL to validate the requested transformations and normalize the URL by ordering transformations and convert them to lower case to increase the cache hit ratio. When an automatic transformation is requested, the function also decides about the best one to apply. For example, if the user asks for the most optimized image format (JPEG,WebP, or AVIF) using the directive format=auto, CloudFront Function will select the best format based on the Accept header present in the request.
  3. If the requested image is already cached in CloudFront then there will be a cache hit and the image is returned from CloudFront cache. To increase the cache hit ratio, we enable Origin Shield, a feature of CloudFront that acts as an additional layer of caching before the origin, to further offload it from requests. If the Image is not in CloudFront cache, then the request will be forwarded to an S3 bucket, which is created to store the transformed images. If the requested image is already transformed and stored in S3, then it is simply served and cached in CloudFront.
  4. Otherwise, S3 will respond with a 403 error code, which is detected by CloudFront’s Origin Failover. Thanks to this native feature, CloudFront retries the same URL but this time using the secondary origin based on Lambda function URL. When invoked, the Lambda function downloads the original image from another S3 bucket, where original images are stored, transforms it using Sharp library, stores the transformed image in S3, then serve it through CloudFront where it will be cached for future requests.


To deploy this solution, follow the steps in this blog. In addition, the blog shows you how to use in with the Image component of Next.JS. Note that the solution allows you to disable storing transformed images in S3, to rely exclusively on CloudFront cache for serving transformed images.

3rd party managed solutions

If you prefer to use a third party managed image optimization solution, then consider available solutions in the AWS Marketplace, such as CloudinaryImageKit.io or Cloudimage. The three of them are either using CloudFront or have integrations with CloudFront if you want to manage your own CloudFront distribution. Such 3rd party providers are specialized in image optimization, can provide advanced SaaS capabilities, but for an additional cost.

Resources

Was this page helpful?