Technical article
Cloudflare R2 vs Amazon S3 for WordPress Media
Compare Cloudflare R2 and Amazon S3 for WordPress media offload, including cost model, delivery, compatibility, consistency, migration, and operational tradeoffs.
Cloudflare R2 and Amazon S3 can both work well as remote storage for a WordPress Media Library. They expose a familiar object-storage model, both can sit behind public delivery domains or CDNs, and both can be used without replacing WordPress attachment records or editor workflows.
The important difference is not “which one can store images.” Both can. The useful comparison is how each provider affects bandwidth cost, AWS integration, delivery architecture, S3 compatibility, operational complexity, and future migration choices.
For WordPress specifically, provider choice should be separated from the offload architecture. WordPress should remain the source of truth for attachment metadata while the original file and generated sizes are tracked as remote objects. That is the model used by KAZCODE Universal Storage.
Short answer
Choose Cloudflare R2 when internet-facing media traffic and outbound bandwidth cost are important, you are comfortable with an S3-compatible service rather than AWS itself, and you want a straightforward path into Cloudflare’s network.
Choose Amazon S3 when your WordPress stack already lives deeply inside AWS, you need AWS-native IAM and service integrations, or you want the broadest possible S3 feature surface rather than compatibility with the subset your WordPress offload workflow needs.
Neither choice removes the need for verification, restore capability, generated-image-size tracking, cache management, and a safe migration plan.
R2 vs S3 at a glance
| Area | Cloudflare R2 | Amazon S3 |
|---|---|---|
| WordPress media offload | Good fit through S3-compatible API | Native S3 target |
| API model | S3-compatible API plus Cloudflare APIs | Amazon S3 API |
| Internet egress model | R2 currently lists internet egress as free | S3 data transfer pricing has chargeable paths and documented exceptions |
| Region configuration | S3 API commonly uses region auto | Bucket belongs to a specific AWS Region |
| AWS ecosystem integration | Limited compared with native AWS services | Deep integration with IAM, CloudFront and other AWS services |
| Strong object consistency | Yes | Yes |
| Migration portability | Familiar S3-style tooling, but not every S3 feature is implemented | Reference implementation for the S3 ecosystem |
| Typical WordPress setup | Bucket + R2 credentials + account endpoint + delivery domain | Bucket + AWS credentials/IAM + Region + delivery/CDN setup |
Provider pricing and API capabilities change. For current details, check the official Cloudflare R2 pricing, Cloudflare R2 S3 compatibility, and Amazon S3 pricing pages before making a production cost decision.
The biggest practical difference: outbound bandwidth
Cloudflare positions R2 around avoiding traditional object-storage egress charges. As of September 2026, its published R2 pricing states that direct egress from R2 does not incur data-transfer charges, including through the S3 API and R2 delivery paths.
Amazon S3 has a more conditional data-transfer model. AWS documents free paths such as data transfer into S3, transfers to CloudFront, same-Region transfers in several cases, and a monthly internet transfer allowance, while other internet or inter-Region transfer paths can be chargeable.
For a WordPress site, that distinction matters because public images can produce far more read traffic than write traffic. A site may upload each image once, then serve that image or one of its generated sizes thousands of times.
That does not automatically mean R2 is cheaper for every site. Your total bill can also include storage, request operations, CDN behavior, image transformation services, cache hit rate, and other provider services. Compare the whole delivery path, not only the per-GB storage line.
S3 compatibility is useful, but it is not identical to Amazon S3
R2 exposes an S3-compatible API, which is why many WordPress storage tools can support it without a provider-specific storage engine. The endpoint format and authentication model look familiar to S3 tooling, and Cloudflare documents the supported operations explicitly.
Compatibility should not be read as “every Amazon S3 feature behaves identically.” Cloudflare’s compatibility matrix lists both implemented and unimplemented S3 features. That is normally fine for a WordPress media workflow that mainly needs operations such as upload, download, HEAD/existence checks, delete, list, and multipart handling, but it is still worth verifying the exact feature set your tooling uses.
KAZCODE Universal Storage treats R2 as a dedicated provider preset. The setup uses the R2 account endpoint, region behavior appropriate for R2, credentials scoped to the bucket, and path-style configuration expected by the plugin’s tested provider path. See the Cloudflare R2 setup docs.
Amazon S3 is the native target. Its provider path uses the bucket Region and AWS S3 configuration directly; custom S3-compatible endpoint settings are not needed for the AWS preset. See the Amazon S3 setup docs.
Consistency: both are strong for normal object operations
It is outdated to assume Amazon S3 is eventually consistent for ordinary object writes. AWS documents strong read-after-write and list consistency for S3.
Cloudflare likewise documents R2 as strongly consistent for object writes, reads, metadata updates, deletes, and listings. One caveat is delivery caching: if you serve an object through a cached custom domain, the cache can continue returning older content or a cached 404 until it expires or is purged.
That cache distinction matters for WordPress. Storage can be correct while the public delivery layer is stale. After overwriting, migrating, or changing delivery configuration, test the object through both the storage API and the public URL path.
Official references:
WordPress-specific architecture matters more than provider branding
A reliable offload plugin should not turn attachment URLs into its only source of truth.
WordPress still needs to know:
- the attachment’s relative upload path
- which generated sizes belong to the attachment
- which remote profile owns those objects
- whether every tracked object actually exists remotely
- whether local copies still exist
- whether an object can be restored
- whether delivery should use local storage, S3, R2, or another profile
KAZCODE Universal Storage keeps WordPress attachment metadata in WordPress and tracks the remote object inventory separately. That makes provider changes safer because the storage target is configuration and inventory state rather than a destructive rewrite of the Media Library.
The broader workflow is documented in Media Offload and Verify Media.
Delivery options
Amazon S3
A common S3 architecture is:
WordPress
|
v
Amazon S3 bucket
|
+--> CloudFront / custom delivery domain
S3 objects do not need to be made public with object ACLs. A CloudFront distribution with appropriate origin access controls is a common production design. The Universal Storage Amazon S3 docs also support configuring a public delivery hostname or CDN/Base URL separately from the storage endpoint.
Cloudflare R2
A common R2 architecture is:
WordPress
|
v
Cloudflare R2 bucket
|
+--> custom domain / Cloudflare delivery path
R2 can also expose an r2.dev domain, but a production site will often use a custom
domain and intentional cache policy.
In both cases, do not confuse storage endpoint and public delivery URL. WordPress writes and verifies against the storage API; visitors should receive media through the delivery path you intentionally configure.
Generated sizes are the real WordPress test
One attachment can represent many files:
photo.jpg
photo-150x150.jpg
photo-300x200.jpg
photo-768x512.jpg
photo-1536x1024.jpg
...
Themes, WooCommerce, responsive srcset, and plugins can request different variants.
A provider setup is not proven because only the original object exists.
A complete test should upload a new image, generate normal WordPress sizes, confirm the variants exist in the remote inventory, render frontend pages, and test restore. The WordPress S3 media offload guide goes through that workflow step by step.
Which is better for WooCommerce?
There is no universal provider answer, but WooCommerce makes bandwidth and variant coverage more important.
Product galleries can generate several image sizes, category grids can create high image request volume, and feeds or integrations may access the same media outside the normal storefront path.
R2’s egress model can be attractive for internet-heavy media delivery. S3 can be attractive when the rest of the commerce stack already depends on AWS and CloudFront. In both cases, the plugin must preserve generated variants and not break attachment metadata.
A dedicated WooCommerce article belongs in the next content phase; provider choice alone does not solve WooCommerce media correctness.
Migrating later: design for reversibility
The safest provider choice is one you can leave without rewriting your Media Library.
If you start on S3 and later want R2, keep S3 authoritative while you:
- configure R2 as a separate destination
- test credentials and connectivity
- copy tracked objects
- verify destination objects
- switch delivery only after verification
- keep the S3 source for a rollback window
- clean up source objects only when you choose to
That process is covered in Move WordPress Media from Amazon S3 to Cloudflare R2 Safely and the S3 to R2 migration docs.
KAZCODE Universal Storage Pro adds multiple profiles and cross-provider migration so the source and destination can coexist during that process.
A practical decision framework
Use these questions instead of choosing from a feature checklist alone.
1. Where does the rest of your infrastructure live?
If your application, CDN, security model, observability, and access control are already centered on AWS, S3 is operationally natural.
If your public delivery is already heavily Cloudflare-oriented, R2 may simplify the storage-to-edge path.
2. How much internet media traffic do you expect?
High public read volume makes data-transfer economics important. Model request volume, storage growth, cache hit rate, and outbound traffic together.
3. Do you need AWS-specific S3 capabilities?
If another application requires S3 features outside R2’s compatibility surface, verify those features explicitly before moving. Do not assume compatibility means complete feature parity.
4. Can you restore and migrate?
Provider lock-in is partly a tooling problem. A WordPress storage setup should keep a known restore path and enough inventory data to verify a future move.
5. What happens when the provider is temporarily unavailable?
A timeout is not the same as a confirmed missing object. Verification and cleanup logic should distinguish unknown/provider errors from real absence before deleting local data.
Recommendation by scenario
New WordPress site with large public media traffic: evaluate R2 early because its current egress model is directly relevant to image-heavy traffic.
WordPress running inside a mature AWS stack: S3 is usually the operationally simplest starting point because IAM, Regions, CloudFront, logging, and surrounding services already fit the same platform.
Existing S3 site considering R2: do not edit the existing profile in place. Use a separate destination and verified migration.
Agency managing different client stacks: favor tooling that abstracts the provider choice and preserves a consistent verify/restore workflow across S3 and S3-compatible providers.
Final point
R2 vs S3 is not a permanent architectural commitment if your WordPress offload layer is designed correctly.
Pick the provider whose cost model and surrounding ecosystem fit the site today, but keep the Media Library portable: track every variant, verify remote objects, preserve restore, and separate transfer from cutover.
Start with the Universal Storage overview, read the Cloudflare R2 guide, or use the Amazon S3 provider documentation to configure the provider you choose.