Skip to main content

Cloudsoft Zone Build, deploy and scale with practical guides to PHP, Node.js, React, DevOps and AI automation. Explore the guides

Cloudsoft Zone
SaaS and CloudComparison

S3, Cloudflare R2 or DigitalOcean Spaces: real storage costs

What object storage really costs a small SaaS: S3 with CloudFront, Cloudflare R2 and DigitalOcean Spaces priced on one workload, with egress traps explained.

Cloudsoft Zone

7 min read

Open red storage pod chassis with rows of empty drive slots and cooling fans, next to server racks and coloured network cables
Photograph: ChrisDag / CC BY 2.0, via Wikimedia Commons
In this article

For a small SaaS that serves user uploads or static assets, the storage price per gigabyte barely matters; what you pay for is data going out to the internet. At the time of writing (October 2026), serving 2 TB a month straight from Amazon S3 costs about $175 in egress alone, the same traffic through CloudFront about $87, from DigitalOcean Spaces about $10, and from Cloudflare R2 nothing, because R2 does not charge for egress.

This comparison uses the providers' published list prices to cost one realistic workload, explains the line items that surprise people, and ends with a short decision guide. Prices change, so the cost model is included as code you can re-run with your own numbers.

Close-up of a reel of black fibre-optic drop cables with red stripes and printed markings
Egress is the cost of sending bytes down cables like these to your users, and it is where storage bills grow.

The price list, side by side

All prices are US dollars, list prices for the default or US region, checked against official pricing pages in October 2026. Taxes are excluded.

ItemAmazon S3 Standard (us-east-1)Cloudflare R2 StandardDigitalOcean Spaces
Storage$0.023 per GB-month (first 50 TB)$0.015 per GB-month$5/month includes 250 GiB, then $0.02 per GiB
Writes$0.005 per 1,000 PUT, COPY, POST or LIST$4.50 per million Class A operationsNo per-request charge listed
Reads$0.0004 per 1,000 GET$0.36 per million Class B operationsNo per-request charge listed
Egress to the internet100 GB/month free across AWS, then $0.09 per GB for the first 10 TBFree1,024 GiB included, then $0.01 per GiB
Free allowanceThe 100 GB egress above10 GB-month storage, 1M Class A, 10M Class B per monthAllowances are part of the $5 subscription
CDNCloudFront, billed separatelyCloudflare cache via a custom domainBuilt-in CDN at no extra cost; counts against transfer

For CloudFront, the pay-as-you-go price in the United States, Mexico and Canada is $0.085 per GB after an always-free 1 TB per month, plus $0.0100 per 10,000 HTTPS requests after 10 million free requests. Fetches from an S3 origin to CloudFront are free. In India the per-GB rate is $0.109.

A worked example: 500 GB stored, 2 TB served

Take a SaaS that stores 500 GB of user files, serves 2 TB (2,048 GB) a month, takes 1 million uploads and serves 20 million downloads. For the CloudFront case, assume 10% of requests miss the cache and go to S3.

SetupMonthly costWhere the money goes
S3 served directly$199.82$175.32 of it is egress
S3 behind CloudFront (pay-as-you-go)$114.34$87.04 CloudFront transfer, $10 requests, $11.50 storage
DigitalOcean Spaces with its CDN$20.24$5 base, $5 extra storage, $10.24 extra transfer
Cloudflare R2$10.95$7.35 storage, $3.60 reads, $0 egress

The calculation, so you can change the inputs and the prices:

JavaScript
// Monthly object storage cost model. Prices: list prices, October 2026.
const usage = { storedGB: 500, egressGB: 2048, writes: 1_000_000, reads: 20_000_000 };

const s3Direct = (u) =>
  u.storedGB * 0.023 +                      // S3 Standard, first 50 TB, us-east-1
  Math.max(0, u.egressGB - 100) * 0.09 +    // internet egress after 100 GB free
  (u.writes / 1000) * 0.005 +               // PUT, COPY, POST, LIST
  (u.reads / 1000) * 0.0004;                // GET

const s3CloudFront = (u, missRate = 0.1) =>
  u.storedGB * 0.023 +
  (u.writes / 1000) * 0.005 +
  ((u.reads * missRate) / 1000) * 0.0004 +  // origin GETs on cache misses
  Math.max(0, u.egressGB - 1024) * 0.085 +  // CloudFront US: 1 TB free, then $0.085/GB
  (Math.max(0, u.reads - 10_000_000) / 10_000) * 0.01; // HTTPS requests after 10M free

const r2 = (u) =>
  Math.max(0, u.storedGB - 10) * 0.015 +              // 10 GB-month free
  (Math.max(0, u.writes - 1_000_000) / 1e6) * 4.5 +   // Class A after 1M free
  (Math.max(0, u.reads - 10_000_000) / 1e6) * 0.36;   // Class B after 10M free; egress free

const spaces = (u) =>
  5 +                                       // includes 250 GiB stored, 1,024 GiB out
  Math.max(0, u.storedGB - 250) * 0.02 +
  Math.max(0, u.egressGB - 1024) * 0.01;

for (const [name, fn] of Object.entries({ s3Direct, s3CloudFront, r2, spaces })) {
  console.log(name.padEnd(13), '$' + fn(usage).toFixed(2));
}

The model treats GB and GiB as equal for Spaces and counts 1 TB as 1,024 GB for the CloudFront free tier, so treat results as estimates within a few per cent. It also ignores tax, the 100 GB AWS free egress in the CloudFront case, and minimum billing rules on infrequent-access classes.

CloudFront's flat-rate plans change the picture

CloudFront now also sells flat-rate plans per distribution with "no additional overage charges": Free ($0, 1 million requests and 100 GB), Pro ($15, 10 million requests and 50 TB), Business ($200, 125 million requests and 50 TB) and Premium ($1,000). They bundle DNS, DDoS protection, AWS WAF rules and S3 storage credits (50 GB on Pro, 1 TB on Business). In the example, 20 million requests exceed the Pro allowance, so the fit would be Business at $200. A site with heavy transfer but fewer than 10 million requests a month would fit Pro at $15, which makes S3 plus CloudFront competitive again. Check how your request count, not just your bandwidth, maps to a plan.

Black-and-white photo of enterprise hard drives in moulded recycled-plastic packaging
Raw capacity is cheap; requests, retrieval fees and minimum durations decide the real price.

What the price tables do not show

Amazon S3

  • Request charges add up on small files. Thumbnails and tiny JSON objects can cost more in GET requests than in storage.
  • LIST is billed like a write. Code that lists a bucket on every page view gets expensive; keep an index in your database.
  • Strengths: the deepest feature set (lifecycle rules, many storage classes, replication, event notifications, fine-grained IAM) and data transfer that is free within AWS to services in the same region.

Cloudflare R2

  • Class A includes ListObjects, at $4.50 per million. As with S3, avoid listing buckets in hot paths.
  • Use a custom domain in production. Cloudflare documents the r2.dev public URL as rate-limited and for development only. A custom domain enables Cloudflare's cache, WAF rules and access controls; by default only certain file types are cached, so add a cache rule if you want everything cached.
  • Infrequent Access is not free to read. R2's Infrequent Access class is $0.01 per GB-month but adds a $0.01 per GB retrieval fee, higher operation prices and a 30-day minimum.
  • Fewer features than S3, and other Cloudflare services connected to a bucket may be billed separately.

DigitalOcean Spaces

  • You pay $5 a month from the first bucket, even if it is empty, until you delete all buckets.
  • CDN traffic counts against transfer. Both origin and CDN traffic use the 1,024 GiB allowance, which is separate from your Droplets' allowance.
  • Cold Storage has small-object rules: objects under 128 KiB are billed as 128 KiB, and each read has a 128 KiB minimum retrieval charge.
  • Strengths: predictable bills, a simple pricing page and an included CDN.

Keep the choice reversible

All three services speak the S3 API, so the cheapest insurance is to write your app against that API and put the endpoint in configuration. With the AWS SDK for JavaScript v3:

JavaScript
import { S3Client } from '@aws-sdk/client-s3';

// Same SDK, different endpoint: switch providers with configuration, not code.
export const storage = new S3Client({
  region: process.env.S3_REGION,            // e.g. 'us-east-1', 'auto' for R2, 'nyc3' for Spaces
  endpoint: process.env.S3_ENDPOINT,        // omit for AWS S3
  credentials: {
    accessKeyId: process.env.S3_ACCESS_KEY_ID,
    secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
  },
});

Store object keys, not full URLs, in your database, and build public URLs from a configurable base URL (your CDN domain). Then moving providers is a bulk copy plus a configuration change, not a data migration.

Which one should you pick?

  • Your app already runs on AWS and traffic is modest: S3 with CloudFront. Compare the Free or Pro flat-rate plan against pay-as-you-go for your request count.
  • Egress is your biggest cost (video, downloads, image-heavy apps, public datasets): Cloudflare R2 with a custom domain.
  • You host on DigitalOcean and want one simple bill: Spaces. Its included 250 GiB and 1,024 GiB cover many early-stage products for $5.
  • Compliance or data-residency rules apply: pick the provider and region that meet them first, then optimise cost within that choice.

What to do next

  1. Pull last month's real numbers: stored GB, GB served, and request counts from your provider's billing or metrics.
  2. Run the cost model with those numbers and with ten times the traffic.
  3. Put a CDN in front of whatever you choose and set long cache lifetimes on immutable, versioned file names.
  4. Set a billing alert at the amount you expect, so a hotlinked file or a runaway LIST loop is caught in days, not at month end.

Frequently asked questions

  • Is Cloudflare R2 egress really free?

    Yes. Cloudflare's R2 pricing page lists egress to the internet as free for both Standard and Infrequent Access storage. You still pay for storage and for Class A and Class B operations beyond the free tier, and Infrequent Access adds a retrieval fee.

  • Does putting CloudFront in front of S3 reduce costs?

    Usually. AWS does not charge for fetches from S3 to CloudFront, CloudFront's per-GB price in the US is lower than S3's internet egress, and it includes 1 TB and 10 million requests free each month. Flat-rate plans from $15 a month can reduce it further if your request count fits.

  • Can I use the AWS SDK with R2 and Spaces?

    Yes. Both offer S3-compatible APIs, so the AWS SDK works with a custom endpoint and the provider's access keys. Check each provider's list of supported S3 operations before relying on advanced features.

  • Should I serve files from the r2.dev URL?

    Not in production. Cloudflare says the r2.dev subdomain is rate-limited and intended for development. Connect a custom domain to use Cloudflare's cache, WAF and access controls.

  • Is DigitalOcean Spaces billed per request?

    The Spaces pricing page lists no per-request charges for Standard Storage: you pay the $5 subscription, storage above 250 GiB at $0.02 per GiB and transfer above 1,024 GiB at $0.01 per GiB. Cold Storage has retrieval fees and a 128 KiB minimum per read.

  • How do I keep the option to switch providers later?

    Use the S3 API through a configurable endpoint, store object keys rather than full URLs, and serve files from your own CDN domain. Switching then needs a bulk copy and a configuration change.

Advertise on CloudSoftZone

Your next customer could start right here.

Introduce your tool, product or business to readers exploring technology.

Advertise with us

Explore placements and request a private quote

Sources

  1. Amazon S3 pricing — Amazon Web Services
  2. Amazon CloudFront pricing (flat-rate plans) — Amazon Web Services
  3. Amazon CloudFront pay-as-you-go pricing — Amazon Web Services
  4. R2 pricing — Cloudflare
  5. R2 public buckets — Cloudflare
  6. Spaces pricing — DigitalOcean

Comments

No comments yet. Be the first to join the conversation.

Leave a comment

Every comment is read by a moderator before it appears. Your email address is never published; it is used only to contact you about this comment.

Never published. Used only to contact you about this comment.

Loading the security check…

Comments are moderated before publication.