Store Magento 2 media in an S3 bucket and serve it through CloudFront. A Lambda@Edge function resizes each image and converts it to AVIF or WebP on the first request. CloudFront caches the result close to the shopper, and Magento stops resizing images on its own server. This post covers the gains, the pitfalls of Magento’s remote storage, and the configuration we use.
Why move Magento 2 images to CloudFront
Smaller files in modern formats
The largest element on a category or home page is often a banner or a product photo. On a phone with a slow connection, an oversized image delays the whole page. Serve each image at the size the page shows it, in a modern format.
A WebP file is usually smaller than the same photo as PNG or JPEG, with no visible loss of quality. AVIF is often smaller still. Current versions of Chrome, Edge, Firefox and Safari display both formats. Keep JPEG or PNG as the fallback for anything else.
Magento stops processing images
Magento’s job is the catalogue, the cart and the checkout. With the CDN in front, the image resizing moves to CloudFront and Lambda@Edge.
CloudFront serves images from the locations closest to your customers, which shortens download times. Doing the same with EC2 instances in several regions means more servers to run, patch and pay for.

Shared images between websites
Some stores show the same images on several websites. For SLF24 we built MyPicture, a module where customers share photos of products in their own homes. Those photos show a product outside the studio and help other shoppers decide.
SLF24 needed one central store for MyPicture images, so every regional website could reuse them. S3 buckets give each website access to the same files. Content specialists import each MyPicture page once, for every region.
Media backups with versioning
S3 bucket versioning keeps the earlier copy of an image when someone overwrites or deletes it. A full media backup copies every file each time. Versioning stores only the files that changed, and you pay only for those. Set a lifecycle rule that removes old versions after a retention period you choose.
Pitfalls of Magento 2 remote storage
Plan the migration before you start.
Stores with many customisations in the CMS need the most care: blog modules, sliders and custom galleries.
Test on staging and keep a backup of pub/media until the store runs clean on S3.
remote-storage:sync is slow
bin/magento remote-storage:sync copies the local media to the bucket.
It uploads one file at a time, and you cannot resume or restart it part of the way through.
On a large catalogue the sync runs for hours, which rarely fits a maintenance window.
The AWS CLI uploads files in parallel, so it finishes the same job much faster. Copy the media with the CLI first, and leave Magento only the files that change afterwards.
The admin captcha breaks
Magento writes captcha images to the local media folder on purpose:
// vendor/magento/module-captcha/Helper/Data.php
public function getImgDir($website = null)
{
// Captcha images are not re-used and should be stored only locally.
$mediaDir = $this->_filesystem->getDirectoryWrite(DirectoryList::MEDIA, Filesystem\DriverPool::FILE);
$captchaDir = '/captcha/' . $this->_getWebsiteCode($website);
$mediaDir->create($captchaDir);
return $mediaDir->getAbsolutePath($captchaDir) . '/';
}
The media URL now points to CloudFront, so the browser asks the CDN for a captcha that exists only on the server.
The image comes back broken and admins cannot log in.
Serve the captcha/ path from the server, or add a CloudFront behaviour that routes it to the server’s origin.
Little control over where files live
Magento’s remote storage decides where each file goes. Sharing images between websites needs more control than that. SLF24’s MyPicture shows the same images on every regional website, with titles and descriptions in each region’s language. Our setup connects Magento to several S3 buckets for cases like this.
Our Magento 2 CloudFront setup
We describe the infrastructure as code in AWS CloudFormation, so each store gets the same CDN setup on demand.
S3 and CloudFront
- Create the S3 bucket in the region where the store’s servers run.
- Create the IAM permissions for Lambda and for Magento’s media connector to reach the bucket.
- Put a CloudFront distribution in front of the bucket.
- Turn on Origin Shield in the region closest to the bucket, for example Ireland for a bucket in Europe.
- Pick the price class that covers your customers, for example North America and Europe.
Lambda@Edge for resizing
- Deploy the Lambda@Edge functions in
us-east-1. CloudFront requires that region for Lambda@Edge. - Write the functions in JavaScript or TypeScript, which most web developers already read.
- Resize with the Sharp library for Node.js, which also writes AVIF and WebP.
- Read the browser’s
Acceptheader and pick AVIF, WebP or the original format. - Add the chosen format to the cache key, so CloudFront keeps one copy per format.
- Allow only the image sizes the theme uses, so nobody can fill the bucket with random sizes.
- Store each converted image in a cache folder in S3.
Magento configuration
Point Magento at the bucket:
bin/magento setup:config:set \
--remote-storage-driver=aws-s3 \
--remote-storage-bucket=<bucket> \
--remote-storage-region=<region>
Copy the media with the AWS CLI instead of remote-storage:sync.
Raise the number of parallel uploads first, then sync to the same path Magento’s remote storage uses in the bucket:
aws configure set default.s3.max_concurrent_requests 64
aws s3 sync pub/media/ s3://<bucket>/<media-path>/ \
--exclude "catalog/product/cache/*" \
--exclude "captcha/*"
Then change three settings in the admin:
- Set the base media URL to the CloudFront domain, for example
https://d1234567890.cloudfront.net/media/. - In Stores > Configuration > General > Web > Url Options, set Catalog media URL format to Image optimization based on query parameters. Magento then asks the CDN for each size through the URL.
- In Stores > Configuration > Advanced > System > Media Gallery Image Optimization, set Enable Image Optimization to No. CloudFront resizes the images instead.
Get help with your Magento 2 media
Category pages that stall while Magento resizes images for new products are a sign this setup pays off. The Magento 2 CDN case study shows the result for a furniture store with several regional websites. A performance audit shows how much of your page weight comes from images. To plan the move itself, tell us about your store.
Frequently asked questions
Magento 2 images on CloudFront
Can CloudFront resize Magento 2 product images?
Yes. A Lambda@Edge function resizes and converts the image on the first request, stores the result in S3 and CloudFront caches it. Magento builds the image URLs with query parameters for width, height and quality once you set the Catalog media URL format to Image optimization based on query parameters.
Should Magento 2 serve AVIF or WebP?
Serve both, chosen by what the browser accepts. AVIF files are often smaller than WebP at the same quality, and current versions of Chrome, Edge, Firefox and Safari display both. Keep JPEG or PNG as the fallback and add the chosen format to the CloudFront cache key.
Why is bin/magento remote-storage:sync so slow?
The command uploads one file at a time and you cannot resume it. On a large catalogue it runs for hours. The AWS CLI uploads files in parallel, so copy the media with aws s3 sync first and leave Magento only the files that change afterwards.
Why does the admin captcha break after moving media to S3?
Magento writes captcha images to the local media folder on purpose, while the media URL now points to the CDN. The browser asks CloudFront for a file that exists only on the server. Serve the captcha path from the server or route it to the server's origin in CloudFront.