Blog · WebJi® India

Offload the WordPress Media Library

Quick answer: Offloading moves uploads out of wp-content/uploads into an S3 or Cloudflare R2 bucket and serves them from a CDN hostname. Install WP Offload Media, add the bucket keys, run the bulk offload, and keep local copies until every image loads from the new URL. Most breakage is a URL that still points at the old path.
✓ In business since 2005✓ INR + GST billing✓ 24/7 Email Support — avg reply < 60 min
Small Indian startup team gathered around a laptop discussing their email inbox — offload wordpress media library cdn

What offloading the media library changes

Offloading keeps every attachment row in the WordPress database and moves the file behind it into an S3 or Cloudflare R2 bucket, which a CDN then serves from its own hostname. The library still lists the image, the post still uses the attachment ID, and only the URL that reaches the browser changes.

  • wp-content/uploads stops growing on the hosting account.
  • Attachment URLs render from the CDN host, not from your domain.
  • The origin keeps serving HTML, PHP and MySQL.
  • Disk savings arrive only when local copies are deleted.

A 2 GB uploads folder on a shared plan is the usual trigger, because every hosting backup and every migration copies it again. Offloading cuts that weight without touching the theme or the editor.

S3 or Cloudflare R2: which bucket to use

Choose R2 when traffic is unpredictable and the bill must stay flat, because R2 does not charge for egress. Choose S3 when the AWS account, IAM policies and CloudFront already exist and the team knows that lane.

BucketHow it billsFits
Amazon S3 + CloudFrontStorage, requests, and every GB deliveredAWS shops, lifecycle rules, multiple regions
Cloudflare R210 GB free, then $0.015/GB-month, no egress fee (Cloudflare figures read 29 Oct 2026)Image-heavy Indian sites with spiky traffic
DigitalOcean SpacesFlat monthly space with a bandwidth allowanceOne-region portfolios and brochure sites
Bunny StoragePer-GB storage plus per-GB deliveryTeams already on Bunny CDN

Put the bucket in the region closest to the people who read the site. Mumbai (ap-south-1) for an Indian audience; a European bucket adds a round trip to every first view, whatever the CDN does later.

Connect WP Offload Media to the bucket

The plugin cannot move anything until the key, the bucket and the CDN hostname are saved. Work in this order and test one upload before the bulk run.

  1. Export the database and download wp-content/uploads: wp db export pre-offload.sql plus an FTP copy. Both are needed if the switch goes wrong.
  2. Create the bucket. On S3, pick ap-south-1 and keep Block Public Access on; on R2, add a custom domain so files have a stable hostname.
  3. Create a key scoped to that one bucket: an IAM user with PutObject, GetObject and DeleteObject on arn:aws:s3:::your-bucket/*, or an R2 API token with Object Read & Write.
  4. Install the plugin with wp plugin install amazon-s3-and-cloudfront --activate for the Lite build, or upload the Pro zip under Plugins, Add New, Upload Plugin.
  5. Open Settings, then WP Offload Media. Choose the provider, paste the key and secret, set the bucket and region, set Path to wp-content/uploads, and switch Force HTTPS on.
  6. Paste the CDN hostname (the CloudFront distribution or the R2 custom domain) into the CDN field and save.

Lite covers Amazon S3 and DigitalOcean Spaces. Cloudflare R2, Google Cloud Storage and the CSS, JS and font offload need the Pro licence; Media Cloud is a free plugin that speaks R2 if you want a trial run.

Rewrite the URLs already in the database

Saving the settings only affects new uploads. Old files keep local URLs until the bulk tool touches them: open Media, then Library, switch to list view, select all, then Bulk actions, Offload. The counter under Settings shows how many attachments still wait.

Large libraries time out in the browser. Run the action on 200 files at a time, or use a plugin that ships a WP-CLI command, for example wp cfr2 offload all --batch-size=100 with a --dry-run pass first.

What the bulk step changes is attachment metadata, not your prose. WordPress asks the plugin for the attachment URL at render time, so the database can still hold /wp-content/uploads/2026/10/photo.jpg while the page shows the CDN hostname. A URL typed into a paragraph, a widget or a page-builder background is not an attachment URL and stays on the old host.

Find those before launch with wp db query "SELECT ID, post_title FROM wp_posts WHERE post_content LIKE '%wp-content/uploads%' AND post_status='publish' LIMIT 30;", then replace the host with a dry run first: wp search-replace 'https://webji.in/wp-content/uploads' 'https://cdn.example.com/wp-content/uploads' --precise --dry-run. Repeat without --dry-run when the report lists only the rows you expect.

What breaks after an offload, and the fix

Nearly every failure after a switch is one of six, and each has a screen or a command that clears it. Check the count under Settings first: if it does not read Offloaded all, nothing else is worth debugging.

SymptomCauseFix
Images still load from your domainThe bulk offload never ran on files uploaded before the pluginMedia, Library, select all, Bulk actions, Offload
Grey boxes instead of thumbnailsOnly the original reached the bucket, not the resized versionsRegenerate thumbnails, then offload the missing sizes
Mixed content warningThe CDN field was saved with http://Change it to https:// and purge the page cache
Fonts or CSS missingThe CDN response carries no Access-Control-Allow-OriginAdd that header at the CDN for font and CSS paths
WooCommerce gallery emptyAn imported CSV stored full image URLs, not attachment IDsRe-import the image column or run the scoped search-replace
Restored backup shows no imagesLocal files were deleted and the hosting backup excludes the bucketKeep a bucket copy or a sync job alongside the account backup

The WordPress image editor also fails once a local file is gone, because cropping reads the file from disk. Leave Remove Local Files off for the first week and delete in one pass after the bucket copy is confirmed.

Verify that the CDN is serving the files

Take a URL from the media library, not from the page source, and ask the CDN directly.

curl -sI https://cdn.example.com/wp-content/uploads/2026/10/photo.jpg

  • 200 with content-type image/jpeg means the object is in the bucket.
  • Cloudflare adds cf-cache-status: HIT on the second request; CloudFront shows x-cache: Hit from cloudfront.
  • cache-control public with a long max-age means the edge will keep it.

Then load the post, view source, and count img tags that start with the CDN host against those that start with your domain. The second count should be zero, apart from images you deliberately kept local. Upload one new image afterwards and confirm its URL already points at the CDN.

Rollback, backups, and where hosting fits

Rollback is a plugin action, not a restore. While local copies exist, use Restore in the media library, or wp cfr2 restore all with the R2 plugin, then deactivate. URLs return to /wp-content/uploads. After local files are deleted the bucket is the only copy, so export it before cancelling storage.

Media offload does not shrink the database, and a database backup still decides whether a restore works. Our WordPress website backup covers files and MySQL on the account, which is why the first week should keep both copies.

The hosting account still runs PHP, MySQL and the page cache. WebJi® WordPress hosting starts at ₹400/month before 18% GST on the WordPress Unlimited plan, includes free Let's Encrypt SSL, and the desk will review an offload setup during a migration. Sites that already serve images from a CDN get the most from the WordPress speed guide, which covers what to fix next.

Frequently Asked Questions

Do I need WP Offload Media Pro for Cloudflare R2?

Yes. The Lite build on WordPress.org connects Amazon S3 and DigitalOcean Spaces only. Cloudflare R2, Google Cloud Storage and the CSS, JS and font offload are sold in the Pro licence, and Media Cloud is a free plugin with R2 support if you want to test first.

Will offloading break existing images?

No, if the bulk offload runs and local copies stay in place until you check. Attachment URLs switch at render time; images pasted into posts, widgets or builder backgrounds as full URLs keep the old host and need a search-replace.

What happens if I deactivate the plugin?

WordPress falls back to /wp-content/uploads. If those files still exist, images load as before; if Remove Local Files already deleted them, every image 404s until you reactivate the plugin or restore the bucket.

How do I check that a file is served from the CDN?

Run curl -sI against the file URL from the media library. A 200 with the right content-type plus cf-cache-status: HIT or x-cache: Hit from cloudfront means the edge has it. Then view source and confirm img tags use the CDN host.

Does offloading free disk space straight away?

No. The database still holds every attachment and the files stay on disk until Remove Local Files runs. The space appears after that pass, and hosting backups shrink on the next run.

Can I keep local copies as a backup?

Yes, WP Offload Media and the R2 plugin both leave local files in place by default. That doubles storage but keeps the rollback cheap, and it is the safer setting for the first month.

Need help with this?

WebJi® support does it for you — free. Talk to our Jaipur team →