Remote Thumbnail Generation
INFO
This feature is available starting with Shopware version 6.6.4.0. The {mediaUpdatedAt} pattern variable was added in 6.6.5.0, and the ResolveRemoteThumbnailUrlExtension hook was added in 6.7.1.0.
In certain scenarios, you might want to disable the filesystem thumbnail generation in Shopware and use an external CDN service to handle the thumbnails. This can be beneficial for performance and scalability reasons. When the remote thumbnail configuration is enabled, the thumbnail images and thumbnail records in the database are not generated by Shopware, but by the external service.
Configuration
To use remote thumbnails, you need to adjust the following parameters in your config/packages/shopware.yaml:
shopware:
media:
remote_thumbnails:
enable: true
pattern: '{mediaUrl}/{mediaPath}?width={width}&ts={mediaUpdatedAt}'| Key | Type | Default | Description |
|---|---|---|---|
shopware.media.remote_thumbnails.enable | bool | false | Master switch. When true, Shopware stops creating, persisting, and deleting thumbnail files and database records and instead synthesizes thumbnail URLs from the configured pattern at request time. |
shopware.media.remote_thumbnails.pattern | string | {mediaUrl}/{mediaPath}?width={width}&ts={mediaUpdatedAt} | Template used to build thumbnail URLs. Variables are listed below. |
The pattern supports the following variables:
mediaUrl: The base URL of the public filesystem (shopware.filesystem.public). For media whosepathis already absolute (e.g., uploaded by URL),{mediaUrl}is replaced with an empty string and the leading slash is trimmed automatically.mediaPath: The media file path relative tomediaUrl(for examplemedia/ab/cd/file.jpg).width: The width from the assignedmedia_thumbnail_sizeof the media folder.height: The height from the assignedmedia_thumbnail_sizeof the media folder.mediaUpdatedAt: Unix timestamp ofmedia.updatedAt, falling back tomedia.createdAt. Empty string when both are null. Useful as a cache-buster (Shopware versions older than 6.6.5.0 do not support this variable).
For example, with the default pattern {mediaUrl}/{mediaPath}?width={width}&ts={mediaUpdatedAt}, the thumbnail URL is generated as https://yourshop.example/abc/123/456.jpg?width=80&ts=1718954838.
WARNING
Private media is intentionally excluded from remote URL generation: it keeps using its signed local URL even while the feature is enabled. Plan accordingly if your shop relies on private media.
Usage
Once the configuration is set, Shopware will automatically use the defined pattern to generate thumbnail URLs. These URLs will point to the external CDN service, which should handle generating and delivering the thumbnail images.
Please note that the external service needs to be able to handle the URL pattern and generate the appropriate thumbnails based on the provided parameters.
Behavior when enabled
Enabling shopware.media.remote_thumbnails.enable short-circuits multiple subsystems. Plugins that interact with thumbnails directly should be aware of the changes:
ThumbnailService—generate(),updateThumbnails(), anddeleteThumbnails()throwMediaException::thumbnailGenerationDisabled()(HTTP 400, error codeMEDIA_THUMBNAIL_GENERATION_DISABLED). Guard custom code that calls these methods.- Message handler —
GenerateThumbnailsHandlerandUpdateThumbnailsHandlerconsume but no longer processGenerateThumbnailsMessage/UpdateThumbnailsMessage. - Media indexer —
MediaIndexer::iterate,update, andhandleearly-return, so noMediaIndexingMessageis enqueued andmedia.thumbnails_rois not maintained (since 6.7.1.0). Runningbin/console dal:refresh:index media.indexeris a no-op. - CLI commands —
bin/console media:generate-thumbnailsaborts withCommand::FAILUREand printsRemote thumbnails are enabled. Skipping thumbnail generation. FileSaver— uploads no longer dispatch aGenerateThumbnailsMessage, and renames skip the thumbnail-rename step (which would otherwise fail because no local thumbnail files exist).MediaDeletionSubscriber— original files are still deleted, but the thumbnail-file enumeration and themedia_thumbnailrow deletion are skipped.MediaUrlLoader— listens tomedia.loaded/media.partial_loadedand delegates toRemoteThumbnailLoader, which synthesizes aMediaThumbnailCollectionin memory based on the media folder's configuredmedia_thumbnail_sizeentries.
WARNING
The synthesized MediaThumbnailEntity instances are assigned a fresh random UUID on every request and are not persisted. Do not rely on media_thumbnail.id being stable, and do not join other tables against it while the feature is on.
Cleaning up local thumbnails
If you switch from local to remote thumbnails on an existing shop, the previously generated media_thumbnail records and files remain in storage. Shopware ships a CLI command (added in 6.6.6.0) that removes them:
bin/console media:delete-local-thumbnailsThe command only runs when remote thumbnails are enabled. It deletes every row from media_thumbnail, removes the corresponding files via the configured filesystem adapter, and clears the serialized media.thumbnails_ro column so that the storefront immediately stops referencing stale entries.
Extending the URL generation
RemoteThumbnailLoader dispatches the URL through the ResolveRemoteThumbnailUrlExtension (extension name remote_thumbnail_url.resolve, available since 6.7.1.0). Apps and plugins can subscribe to it to:
- rewrite the URL (for example, sign it, route it through an image-resizing proxy, swap the host per sales-channel),
- return
nullto skip a thumbnail entirely (since 6.7.3.0), - read the full
MediaEntityto make decisions based onmimeType, custom fields, or folder configuration.
Subscribe to the extension via the standard extension event mechanism. Do not modify MediaUrlLoader or RemoteThumbnailLoader directly; both are marked @final and may change.
Invalidating Thumbnails with Fastly
If you are using Fastly as your CDN, you can let Shopware invalidate the cached thumbnails when media is updated. To do this, configure your Fastly API key in your config/packages/shopware.yaml:
shopware:
cdn:
fastly:
api_key: '%env(FASTLY_API_KEY)%'
soft_purge: false
max_parallel_invalidations: 2| Key | Type | Default | Description |
|---|---|---|---|
shopware.cdn.fastly.api_key | string | '' | Personal Fastly token. Setting this to a non-empty value is what activates media invalidation — there is no separate enabled flag. With an empty key, the listener silently no-ops. |
shopware.cdn.fastly.soft_purge | bool/string | false | Sent verbatim as the fastly-soft-purge request header. Set to true (or '1') to keep serving stale content while purges propagate. |
shopware.cdn.fastly.max_parallel_invalidations | int | 2 | Guzzle pool concurrency for purge requests. Bounds how many POST https://api.fastly.com/purge/{url} calls are in flight simultaneously. |
When media changes (path change, file update, or deletion), the BanMediaUrl listener resolves all affected URLs and dispatches them through FastlyMediaReverseProxy, which sends one purge request per URL. Failures are logged at critical level and do not block the write process.
INFO
This is the media-cache Fastly configuration node. It is independent from shopware.http_cache.reverse_proxy.fastly, which configures the storefront's HTTP-cache invalidation gateway and exposes additional options such as service_id, instance_tag, and tag_prefix. See Reverse HTTP cache for the storefront side.
Conclusion
By using remote thumbnails, you can offload the task of thumbnail generation to an external service, potentially improving the performance and scalability of your Shopware installation.