- Offloading solves a storage problem, not a speed problem. A CDN in front of local files is usually the faster answer.
- It is worth doing when the media library is very large, when several servers must share it, or when storage cost is the constraint.
- Keep a local copy until you have verified everything. Deleting local files is the step that cannot be undone.
- Choose a region near your visitors. A UK audience served from a US bucket adds latency to every image.
- Every offload plugin rewrites URLs in the database. Test with the rewriting disabled before you commit to it.
Should I offload WordPress media at all?
Only if storage is your actual constraint. Offloading moves files off the server, which helps with disk space, backup size and sharing media between servers. It does not make images load faster on its own, and done carelessly it makes them slower by adding a DNS lookup and a connection to a distant host.
| Problem | Offloading helps? | Better answer |
|---|---|---|
| Images load slowly | No | A CDN, plus compression and correct sizing |
| Running out of disk space | Yes | Offloading, or a larger disk |
| Backups take hours | Yes | Offloading, or excluding media from the nightly job |
| Several servers need the same media | Yes | Offloading, or shared storage |
| Storage costs are high | Yes | Object storage is far cheaper per gigabyte |
| Poor Core Web Vitals | No | Image format, dimensions and lazy loading |
Rows one and six are the common reasons people offload, and offloading is the wrong tool for both.
A CDN in front of local files is usually the better first step
It gives you the speed benefit with none of the migration risk: files stay where they are, URLs do not change, and there is nothing to undo if you change your mind. Offloading is worth doing when the volume of media itself is the problem.
cd /var/www/example.com
# Total media size
du -sh wp-content/uploads
# By year, so you can see the growth
du -sh wp-content/uploads/*
# How many files?
find wp-content/uploads -type f | wc -l
# The largest individual files
find wp-content/uploads -type f -size +2M -exec ls -lh {} \; \
| awk '{print $5, $9}' | sort -rh | head -20
# Disk headroom
df -h .How should I choose where to put the files?
Two things decide it: where your visitors are, and whether the provider charges for reading the data back out. Egress fees are the cost people do not model, and on an image-heavy site they can dwarf the storage bill.
| Consideration | Why it matters |
|---|---|
| Region | A UK audience served from a US region pays the round trip on every image |
| Egress charges | Some providers charge per gigabyte served; some charge nothing |
| S3 API compatibility | Nearly every WordPress plugin speaks S3. Non-S3 storage narrows your options sharply |
| CDN in front | Essential. Serving directly from a bucket is slower than serving from your own server |
| Data residency | UK or EU storage may be required by your own contracts or policies |
Egress is the line to check first. Storage at a low price per gigabyte with high egress can cost more than a plain disk.
A bucket without a CDN is a step backwards
Object storage is built for durability, not for low-latency delivery to browsers. Serving images straight from a bucket typically adds latency compared with your own web server. Always put a CDN in front, and check it is actually caching rather than passing every request through.
How do I migrate media without breaking image URLs?
The order matters. Copy first, verify, switch the URLs, verify again, and only then consider removing anything locally. Each step is reversible until the last one.
- 1Back up the database and the uploads directory. The plugin will rewrite URLs across the database, and you want the pre-change state available.
- 2Copy the files up, leaving the originals in place. Use rclone or the provider's CLI. Nothing on the site changes at this point.
- 3Verify the copy by comparing file counts and total size on both sides.
- 4Install and configure the offload plugin, but leave URL rewriting off. Confirm it can list and write to the bucket.
- 5Turn on URL rewriting and check pages, the media library, and any theme or plugin that builds image URLs itself.
- 6Leave the local files alone for at least two weeks. They are your rollback. Deleting them is the only irreversible step.
# Configure the remote once, interactively
rclone config
# Dry run first: shows what would transfer, changes nothing
rclone sync --dry-run wp-content/uploads/ myremote:my-bucket/uploads/
# The real copy, with progress
rclone sync --progress --transfers=8 \
wp-content/uploads/ myremote:my-bucket/uploads/
# Verify: counts and sizes must match
find wp-content/uploads -type f | wc -l
rclone size myremote:my-bucket/uploads/
du -sb wp-content/uploads
# Byte-level check on a sample
rclone check wp-content/uploads/ myremote:my-bucket/uploads/ --one-wayrclone check compares checksums rather than just sizes. Worth running on a sample before you trust the copy.Never let the plugin delete local files on the first pass
Most offload plugins offer to remove the local copy after upload. Leave that off until you have run for at least two weeks with everything verified. If the rewriting turns out to be wrong, or the plugin is abandoned, local files are the only route back that does not involve a restore.
# How many attachment URLs still point locally?
wp db query "SELECT COUNT(*) FROM wp_posts
WHERE post_type='attachment' AND guid LIKE '%example.com/wp-content/uploads%'"
# Image URLs hardcoded inside post content: these are the ones
# plugins often miss
wp db query "SELECT ID, post_title FROM wp_posts
WHERE post_content LIKE '%/wp-content/uploads/%' LIMIT 20"
# Any broken images on the homepage?
curl -s https://example.com/ \
| grep -oE 'src="[^\"]*\.(jpg|png|webp|avif)"' \
| cut -d'\"' -f2 | sort -u | while read -r u; do
code=$(curl -s -o /dev/null -w '%{http_code}' "$u")
[ "$code" = 200 ] || echo "$code $u"
doneWhat usually goes wrong?
| Problem | Cause | Fix |
|---|---|---|
| Images broken after switching | Content URLs were not rewritten | Search-replace across post_content as well as guid |
| Media library shows blank thumbnails | Bucket permissions block public reads | Allow public read on the objects, or serve via the CDN |
| New uploads stay local | Plugin not configured for new media | Enable upload-on-add in the plugin settings |
| Images slower than before | No CDN, or a distant region | Put a CDN in front and choose a nearer region |
| Large egress bill | Every image request bills the origin | Check the CDN is caching and not passing through |
| Cannot regenerate thumbnails | WordPress cannot read the source locally | Regenerate before offloading, or keep local copies |
Rows one and six are why the local copies stay until you are certain.
# ALWAYS dry run first
wp search-replace 'https://example.com/wp-content/uploads' \
'https://cdn.example.com/uploads' \
--dry-run --report-changed-only
# Then for real, skipping the tables that must not be touched
wp search-replace 'https://example.com/wp-content/uploads' \
'https://cdn.example.com/uploads' \
--skip-columns=guid \
--skip-tables=wp_users,wp_usermeta
# Serialised data is handled correctly by wp search-replace.
# A raw SQL UPDATE will corrupt it. Never use SQL for this.Never do a URL replace with raw SQL
Serialised PHP stores the length of every string alongside it. Changing the text with an SQL UPDATE leaves the lengths wrong and the data unreadable, which usually shows up as plugin settings silently reverting to defaults. wp search-replace understands the format and rewrites the lengths.
What actually makes images load faster?
If the goal was speed rather than storage, these are the changes that produce it, in order of impact. None of them require moving a single file.
- 1Serve the right dimensions. A 4000 pixel original scaled down by the browser transfers the full file and then throws most of it away. This is the largest single win on most sites.
- 2Use WebP or AVIF. Typically 25 to 50 percent smaller than JPEG at the same visual quality, and supported by every current browser.
- 3Lazy load anything below the fold, but never the main hero image. Lazy loading the largest visible element delays the one thing your Largest Contentful Paint depends on.
- 4Set width and height on every image, so the browser reserves space and the page does not jump as images arrive. That is a Cumulative Layout Shift fix.
- 5Put a CDN in front, wherever the files live, so a visitor in Glasgow is not fetching from a single origin every time.
- 6Set long cache headers. Images rarely change; a one-year max-age on versioned filenames is safe and removes repeat transfers entirely.
Those six changes usually beat any storage decision. Core Web Vitals for WordPress covers how each one maps to the metric it affects, and why WordPress performance should not depend on plugins covers the server side underneath them.
Check whether you need to solve this yourself
Storage limits are the usual reason people offload, and generous storage plus caching in front of it removes the reason entirely. On G7Cloud each site has its own storage allowance with usage visible in the dashboard, so you can see whether media is genuinely the constraint before rebuilding how your site serves images. See pricing and allowances.
Frequently asked questions
Does offloading media to S3 make WordPress faster?
Not by itself, and often the opposite. Object storage is built for durability rather than low-latency delivery, so serving directly from a bucket is usually slower than serving from your own server. The speed comes from the CDN you put in front, which you can add without offloading anything.
When is offloading WordPress media worth it?
When storage itself is the constraint: a very large media library, backups that take too long because of it, several servers needing the same files, or storage cost. Below roughly 20 GB the complexity usually is not worth it.
Should I delete local files after offloading?
Not for at least two weeks, and not until you have verified every image resolves. The local copy is your only rollback if URL rewriting turns out to be wrong or the plugin is abandoned. Deleting is the one step in the process that cannot be undone.
Why are my images broken after offloading?
Almost always URLs inside post content that the plugin did not rewrite, since many only handle the attachment records. Check with a query against post_content, then fix with wp search-replace, which handles serialised data correctly. Never use a raw SQL UPDATE for this.
Which storage region should a UK site use?
One in the UK or western Europe. A US region adds a transatlantic round trip to every request that misses the CDN cache. Data residency may also matter if your own contracts specify where customer data is held.
Can I undo a media offload?
Yes, if you kept the local files: reverse the URL rewriting with wp search-replace and deactivate the plugin. If you let it delete the local copies, you have to sync everything back down from the bucket first, which on a large library takes time and bandwidth you will be billed for.
About G7Cloud Engineering
Articles written by the engineers who build and run G7Cloud: UK managed hosting and the AI Website Builder. We write about what we operate every day: containers, backups, databases, and the small-business websites that run on them.
More about G7Cloud →