
Magento 2 never serves your original product photos. It resizes each image to every size defined in the active theme’s view.xml and stores the copies under pub/media/catalog/product/cache/<hash>/. If those copies do not exist yet, the first visitor triggers the resize, which is why new launches, theme changes and cache flushes make category pages slow.
The fix is to generate the cache before shoppers need it, and to keep it from growing without limit afterward. This guide explains how the cache is built, the three ways to pre-generate it (and why the obvious command is the slowest), and the operational habits that keep a large catalog’s image cache fast and a sensible size on Adobe Commerce and Magento Open Source.
How the product image cache is built
Every theme declares the image sizes it needs in etc/view.xml, under <images module="Magento_Catalog">. Adobe’s theme configuration guide lists the attributes each <image> entry can set:
id: a unique name, such ascategory_page_gridorproduct_page_image_medium.type: the Admin image role it uses, one ofimage,small_image,thumbnail,swatch_imageorswatch_thumb.widthandheightin pixels.constrain,aspect_ratio,frameandtransparency, all defaulting to true, plus an optionalbackgroundcolor as[R, G, B].
Adobe states that each product image is resized according to this metadata and that the resized copies are stored in /pub/media/catalog/product/cache, which is where the storefront serves them from. Inside that folder, Magento creates a subdirectory per set of image parameters. The directory name is a hash built from the processing parameters (dimensions, quality, background, frame and similar), not from the photo itself. So one product photo becomes many files: one per distinct size and option combination the active themes ask for.
Three consequences follow, and they explain most image cache problems:
- The cache is derived, not source data. You can delete it and Magento will rebuild it. The only cost is the time and CPU to rebuild.
- Changing a size creates a new directory. Edit a
widthinview.xml, or switch to a theme with different sizes, and Magento starts writing to a new hash folder. The old one stays on disk until someone removes it. - Missing files are generated on request. If a page asks for a cached size that does not exist, Magento resizes the original during that request. One product is fast enough. A category page of 36 products on a cold cache is not.
| Event | What happens to the image cache | Action needed |
|---|---|---|
| New product saved with images | Copies are generally created on save | None for normal Admin saves |
| Bulk import of products and images | Many originals with no cached copies | Pre-generate before traffic arrives |
view.xml size or option changed |
New hash directory, old one orphaned | Pre-generate, then remove the old directory |
| New theme, such as a Luma to Hyva move | New sizes if dimensions differ, so new directories | Pre-generate before launch |
| “Flush Catalog Images Cache” clicked | Entire cache deleted | Full regeneration, ideally off-peak |
| Media moved to remote storage | Cache must exist on the new backend | Plan resizing for the storage model |
Why catalog:images:resize is so slow
The command everyone reaches for is:
bin/magento catalog:images:resize
It works, and on a small catalog it is fine. On a large one it is the slowest option available. Adobe’s catalog image resizing best practices lists its drawbacks plainly: it is single-threaded, it reprocesses images that are already resized, it cannot be interrupted, and it can take days. The same page gives a comparison for 100,000 images: under 8 hours using the request-based method described below, against 6 days for the CLI command.
Adobe’s playbook also makes the stakes clear. If images are not resized before a store goes live, resizing happens during page loads, which slows the site and raises server load for days to weeks after launch. That is the “the new site is slow” complaint many launches hit in week one, and it has nothing to do with the theme or the hosting plan.
Common failure modes with the synchronous command:
- Memory limits. Long runs on big catalogs can exhaust PHP’s memory limit. Running with a higher
memory_limitfor the CLI process is the usual workaround. - A broken original stops progress. A zero-byte or corrupt source file can throw an error partway through. Find and fix the bad file, then rerun.
- Restarting from zero. Because it redoes work already done, a crash at hour 20 costs you the full run again.
The faster options: async queue and request-based warming
There are two better ways to pre-generate the cache, both documented by Adobe.
Option 1: the asynchronous queue
Since 2.4, the command can push work onto a message queue instead of resizing in a single process. Adobe’s playbook recommends temporarily starting extra consumers on every web server, set to twice the number of physical processors per server:
bin/magento queue:consumers:start media.storage.catalog.image.resize &
pgrep -fl media.storage.catalog.image.resize
bin/magento catalog:images:resize --async
The first line starts a consumer (repeat it to start more), the second confirms they are running, and the third fills the queue. When the queue is drained, stop them:
pkill -f media.storage.catalog.image.resize
This turns a single-threaded job into a parallel one using the queue infrastructure Magento already has. If your consumers are normally managed by cron or Supervisor, make sure the extra ones do not fight with your usual setup, and stop them afterward so they do not hold memory on web nodes. Our guide to keeping Magento message queue consumers alive with Supervisor and cron covers how consumers are normally run.
Option 2: warm the cache through the web server
The fastest method in Adobe’s playbook is to request every cached image URL through the web server, so normal PHP-FPM workers on every node generate the images in parallel. Adobe notes that this method is multi-threaded, works across multiple servers (with a load balancer and shared media/ storage), and skips images that are already resized. Requesting one cache URL generates all sizes for that image in the background if they do not exist yet.
The approach in outline:
- On the server, list the originals under
pub/media/catalog/product. - Note one existing hash directory name under
cache/. - Turn the file list into cache URLs on your domain using that hash.
- Request them in parallel with a tool such as
curldriven byxargs -P, orsiege, tuning the concurrency to what the servers can take.
Adobe’s playbook includes the exact find, sed and xargs one-liner. The key operational point is the concurrency setting. Too low and you lose the speed advantage. Too high and you are effectively load-testing production. Run it before launch or off-peak, and watch CPU and PHP-FPM queue length while it runs. If the full page cache also needs warming after launch, do the images first, since page warming on a cold image cache doubles the work. Our piece on full page cache warming on Magento and Hyva covers the warm order.
| Method | Parallel | Skips already resized | Interruptible | Best for |
|---|---|---|---|---|
catalog:images:resize |
No | No | No | Small catalogs, one-off fixes |
catalog:images:resize --async + consumers |
Yes, per consumer | Depends on queue contents | Stop consumers to pause | Medium and large catalogs on 2.4+ |
| Request cache URLs through the web server | Yes, across nodes | Yes | Yes, just stop the requests | Launches and very large catalogs |
| CDN or nginx image resizing | Handled outside PHP | Yes | Not applicable | Cloud with Fastly, or remote storage setups |
Cloud and remote storage change the picture
Two notes from Adobe’s playbook are worth knowing before you plan any of the above:
- Adobe Commerce on cloud infrastructure can hand product image resizing to Fastly through its deep image optimization feature, which takes the work out of PHP entirely.
- Remote storage, such as Amazon S3, can offload image resizing to nginx instead of Magento, according to Adobe’s configuration guide.
If your media is already on S3 or you are planning that move, read our guide to Magento remote storage on Amazon S3 before you warm anything, because where the cache is written and how it is served both change.
Keeping the cache from filling the disk
Because the cache is derived and Magento never prunes it, it only grows. A few habits keep it under control.
Remove orphaned hash directories after size changes. When you change view.xml or switch themes, generate the new sizes first, confirm the storefront is serving from the new hash folders, then delete the old ones. Deleting first means shoppers trigger regeneration.
Do not use “Flush Catalog Images Cache” casually. The button in System > Cache Management deletes the entire product image cache. It is the right tool after a bulk image replacement, but on a large catalog it throws away hours of work, and the next visitors pay for the rebuild. Schedule it off-peak, followed by one of the warming methods above.
Cap original upload sizes. Oversized originals make every resize slower and every cached variant heavier. In the Admin under Stores > Settings > Configuration > Advanced > System, the Images Upload Configuration section has an “Enable Frontend Resize” option. Adobe’s product image configuration docs list default maximums of 1920 pixels wide and 1200 pixels high, keeping proportions. For imports that bypass the Admin, resize originals before they reach the server.
Keep the number of sizes honest. Every <image> entry in view.xml can mean another file per product photo. Themes often inherit sizes they never render. Remove entries the storefront does not use, and you remove a share of the cache you generate and store. Serving modern formats changes the picture again, covered in our piece on WebP and AVIF images on Hyva Magento.
Watch disk space and file counts, not just gigabytes. Image caches hold huge numbers of small files. File systems can run out of inodes before they run out of space, and backups and rsync slow down as file counts grow. Exclude the cache directory from backups, since it can always be regenerated.
A launch checklist for product images
Before a new store, a new theme, or a major catalog import goes live:
- Confirm the final
view.xmlsizes for the production theme. Changing them after warming means warming again. - Clean or resize oversized originals.
- Pre-generate the cache with the async queue or request-based warming, sized to your catalog.
- Spot-check that category and product pages return images from the new hash directory with no resizing in the request.
- Remove orphaned hash directories from the old theme or sizes.
- Warm the full page cache only after images are in place.
- Set a monitoring alert for disk and inode usage on the media volume.
How Bemeir handles product images on Magento builds
Bemeir is a Brooklyn agency for Magento, Adobe Commerce and Hyva builds. On a Luma to Hyva project through Hyva development services, the image cache is one of the items worth planning for explicitly, since a new theme with different image dimensions means a new cache, and a cold cache on launch day can hide how fast the new frontend actually is. On wider Magento development services work, the same checklist applies to imports, migrations and storage changes.
Other platforms handle this differently. A Shopify development or BigCommerce development project hands image resizing to the platform’s own CDN, while Shopware development generates thumbnails on the server, much like Magento, so the same warming and pruning ideas carry over. For CDN and image optimization vendors, see the Bemeir technology partners page, and read About Bemeir for more on the team.
FAQ
Where does Magento 2 store resized product images?
In pub/media/catalog/product/cache/, inside subdirectories named with a hash of the image parameters such as size and background. The storefront serves images from that cache, not from the originals in pub/media/catalog/product/.
Why does catalog:images:resize take so long?
Adobe documents that the command is single-threaded, reprocesses images that are already resized, and cannot be interrupted. Adobe’s own comparison for 100,000 images is about 6 days for the CLI command against under 8 hours when warming through web requests.
How do I resize Magento images faster?
On 2.4 and later, run bin/magento catalog:images:resize --async with several media.storage.catalog.image.resize consumers running, which Adobe suggests setting to twice the physical processors per server. The fastest option is requesting every cache URL through the web server in parallel.
Is it safe to delete pub/media/catalog/product/cache?
Yes, the files are regenerated from the originals. The cost is performance: until the cache is rebuilt, page requests resize images on the fly. Delete it off-peak and run a warming method straight after.
Why are my product images slow after switching themes?
A theme with different image dimensions in view.xml produces new hash directories, so the existing cache no longer matches. Every image is resized again on first request until you pre-generate the new sizes.




