Performance8 min readPublished: 22 Apr 2025Updated: 29 Jul 2026

Offloading WordPress Media to External Storage

When moving WordPress media to object storage helps and when it hurts, how to migrate safely, and the mistakes that break image URLs or slow a UK site down.

G7Cloud Engineering
Platform team
Share:
Abstract illustration representing offloading wordpress media to external storage.
  • 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.

ProblemOffloading helps?Better answer
Images load slowlyNoA CDN, plus compression and correct sizing
Running out of disk spaceYesOffloading, or a larger disk
Backups take hoursYesOffloading, or excluding media from the nightly job
Several servers need the same mediaYesOffloading, or shared storage
Storage costs are highYesObject storage is far cheaper per gigabyte
Poor Core Web VitalsNoImage 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.

How big 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 .
Under about 20 GB, offloading rarely pays for its complexity. Above 100 GB it usually does.

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.

ConsiderationWhy it matters
RegionA UK audience served from a US region pays the round trip on every image
Egress chargesSome providers charge per gigabyte served; some charge nothing
S3 API compatibilityNearly every WordPress plugin speaks S3. Non-S3 storage narrows your options sharply
CDN in frontEssential. Serving directly from a bucket is slower than serving from your own server
Data residencyUK 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.

  1. 1Back up the database and the uploads directory. The plugin will rewrite URLs across the database, and you want the pre-change state available.
  2. 2Copy the files up, leaving the originals in place. Use rclone or the provider's CLI. Nothing on the site changes at this point.
  3. 3Verify the copy by comparing file counts and total size on both sides.
  4. 4Install and configure the offload plugin, but leave URL rewriting off. Confirm it can list and write to the bucket.
  5. 5Turn on URL rewriting and check pages, the media library, and any theme or plugin that builds image URLs itself.
  6. 6Leave the local files alone for at least two weeks. They are your rollback. Deleting them is the only irreversible step.
Copy and verify with rclone
# 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-way
rclone 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.

Check the URLs actually changed
# 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"
    done
That last loop prints only failures. An empty result means every image on the page resolves.

What usually goes wrong?

ProblemCauseFix
Images broken after switchingContent URLs were not rewrittenSearch-replace across post_content as well as guid
Media library shows blank thumbnailsBucket permissions block public readsAllow public read on the objects, or serve via the CDN
New uploads stay localPlugin not configured for new mediaEnable upload-on-add in the plugin settings
Images slower than beforeNo CDN, or a distant regionPut a CDN in front and choose a nearer region
Large egress billEvery image request bills the originCheck the CDN is caching and not passing through
Cannot regenerate thumbnailsWordPress cannot read the source locallyRegenerate before offloading, or keep local copies

Rows one and six are why the local copies stay until you are certain.

Fixing URLs left behind in content
# 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.
Plugin settings are stored as serialised PHP, where string lengths are recorded. A SQL find-and-replace breaks them permanently.

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.

  1. 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.
  2. 2Use WebP or AVIF. Typically 25 to 50 percent smaller than JPEG at the same visual quality, and supported by every current browser.
  3. 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.
  4. 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.
  5. 5Put a CDN in front, wherever the files live, so a visitor in Glasgow is not fetching from a single origin every time.
  6. 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.

Put this into practice on G7Cloud

Every site runs in its own dedicated container behind ScaleShield, with daily backups that are restore-tested every night. Start on the free plan, no card needed.

About G7Cloud Engineering

Platform team

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 →