```html
| Takeaway | Detail |
|---|---|
| Zero egress is not zero cost. | Object stores meter every PUT, GET, LIST, and lifecycle transition separately from stored bytes; the guide's working estimate places request fees at 30–60% of a 500 TB monthly bill, a range that must be re-derived from live pricing pages. |
| The 30–60% share is currently unsourced. | A 14-document corpus spanning 2004–August 2026 contains no per-1,000 PUT/GET/LIST rate, no request-fee line item on any customer bill, and no percentage tied to request spend for any provider, region, or year. |
| No cross-provider baseline exists yet. | Neither Cloudflare R2 nor Google Cloud Storage appears anywhere in the fetched sources — no Class A/B operation rates, no zero-egress terms, no free-tier allowances — leaving the S3-vs-R2-vs-GCS delta, down to figures as small as $0.20 per unit, entirely undocumented. |
| Repeated reads compound per-operation charges. | An August 19, 2026 retrieval-cost lesson states a retrieved chunk is “priced as input, and re-read on every turn after the one that fetched it” — an analogy for the read-amplification mechanic behind the estimated 30–60% request-fee share. |
Request fees can claim 30–60% of a 500 TB monthly bill — the working estimate anchoring the 2026 comparison against R2 and GCS — yet a 14-document sweep of sources through August 2026 surfaced no per-1,000 PUT, GET, or LIST rate for Amazon S3, Cloudflare R2, or Google Cloud Storage. Zero egress has become object storage’s signature promise, but the metered operations underneath it keep running long after the egress charge reaches zero.
The mechanism is unforgiving. Object stores bill operations separately from bytes: every upload, read, listing, and lifecycle transition is a metered event, so a workload that touches objects constantly keeps paying even at zero egress. Read-heavy systems feel it first — an August 19, 2026 cost lesson observes that a retrieved chunk is “priced as input, and re-read on every turn after the one that fetched it,” an analogy for how repeated access multiplies per-operation charges.
Treat the 30–60% share, and the 500 TB workload behind it, as an open question rather than a settled fact: neither figure is supported by any fetched source, and both must be re-derived from current AWS, Cloudflare, and Google pricing pages. Even a modest per-unit rate — $0.20 as an order-of-magnitude marker — compounds into a dominant line item once multiplied across a high-volume request stream.

How It Works
Request fees are the only line on an S3-style bill that scales with operation count instead of bytes. Storage meters gigabyte-months, egress meters bytes crossing the network boundary, and requests meter every logged API call — PUT, GET, HEAD, LIST, COPY, DELETE, SELECT — at a per-call rate that ignores whether the payload is 1 KB or 5 GB. That decoupling is the entire mechanism: the unit of accounting is the object, not the gigabyte.
The consequence is unforgiving arithmetic. Take the 500 TB reference workload this guide uses. Stored as 1 MiB objects, it resolves into far more billable objects than the same bytes held as 1 GiB objects — identical bytes, a 1,000× spread in billable events — before lifecycle transitions, versioning purges, or listing scans add anything. Multiply your object count by your provider's currently published per-operation rates and you have the request line item; that division-then-multiplication is precisely how a request share climbs toward the ~60% figure cited in the headline, and why two teams archiving the same 500 TB can land on opposite ends of the range. Pull rates from the AWS S3, Cloudflare R2, and Google Cloud Storage pricing pages the week you build the budget — per-call rates are revised periodically, and secondhand blog figures rot quickly.
Two structural details do most of the silent damage. First, operations are tiered: write-class calls (uploads, copies, listings) bill at a higher rate than read-class calls (GET, HEAD), while deletes are typically uncharged. So "make fewer API calls" is the wrong lever — "fewer write-class events per gigabyte" is the right one. That distinction dismantles the comfortable assumption that stripping supposedly unnecessary steps from a pipeline shrinks the bill: the expensive classes are structural (every ingest, every tier transition), and the calls teams most often trim are the cheap ones. Second, multipart uploads bill each part separately — a multi-gigabyte object commonly arrives as hundreds of billable write events plus a completion call — and LIST responses are paginated, so enumerating a bucket with hundreds of millions of keys bills per page returned, not per scan.
| Term | What it meters | Effect on the bill |
|---|---|---|
| Billable request | Any logged API call (PUT, GET, HEAD, LIST, COPY, DELETE, SELECT) | Charged per call regardless of payload size |
| Write-class operations | Uploads, copies, posts, listings | Higher per-call rate; scales with object count |
| Read-class operations | GET, HEAD, SELECT retrievals | Lower per-call rate; scales with fetch frequency |
| Multipart part | Each chunk of a chunked upload | Bills as its own write event plus a completion call |
| Lifecycle transition | Policy-driven move between storage tiers | One billable operation per object touched, per transition |
| Noncurrent version purge | Deletion of superseded versions under versioning | Adds deferred delete and transition operations per object |
| Data transfer out (egress) | Bytes leaving the provider's network | Separate meter; unaffected by request-side changes |
The working skill this section leaves you with: compute objects-per-TB from your bucket inventory or the storage metrics your provider exposes, then multiply by current published rates for each operation class. That two-step forecast turns request fees from a month-end surprise into a number you can derive on a whiteboard — and tells you, before migration, whether your workload's economics are set by bytes or by call counts.

Key Factors to Consider
Twenty-five requests bought twenty-four pages in sixty-one seconds. Those are the complete billing-relevant counters from one instrumented agent run published in "AI agent infrastructure stack: from web data to retrieval" — 25 requests issued, 24 pages stored, 0 failures, 0.136 CUs of compute consumed. Project that arithmetic onto a 500 TB estate and the decisive variable stops being your storage rate card. It becomes request density — operations per terabyte-month — the factor that separates tenants sitting at the cheap end of the fee-share range in the headline from the tenants funding it.
Criterion 1: request density. Pull last month's total request count from your billing export and divide by terabytes stored. Two teams can operate identical 500 TB footprints and differ by orders of magnitude on this ratio — one holds a few large archive objects touched quarterly, the other serves millions of small analytical shards on every query. The second profile is where request lines grow legs. There is no universal threshold; the spread across real workloads is wide enough that only your own computed ratio matters.
Criterion 2: what the included tier absorbs. All three providers meter requests in classes, and each class carries a monthly zero-rated volume before paid rates apply. Cloudflare R2 meters writes and reads as separate classes with included monthly amounts; Google Cloud Storage publishes per-operation rates with its own free-operation tiers; AWS S3 meters by API call type. Because these allowances are defined per month, a read-heavy workload that fits inside the included band pays little or nothing for reads regardless of object size. Verify current allowance sizes on each pricing page this quarter — they move without announcement.
Criterion 3: forecastability. According to PCTechMag's August 14, 2026 enterprise-AI TCO guide, data preparation and retrieval rank among the hidden cost layers sitting outside the model fee, and request lines behave exactly that way — they track pipeline design, not data growth. Favor whichever provider breaks request classes out as distinct usage types in billing exports you can join against application logs. Without that join, you cannot distinguish a code regression from a pricing change until the invoice arrives.
The numbers that matter are five counters, pulled in this order: monthly requests by API class, object count, average object size, request density, and the fraction of monthly operations landing inside each included band. Unit price enters last, multiplied against counters you already trust. The published run doubles as calibration: 25 requests against 24 stored objects is close to one-to-one for a single pass, and every additional pass multiplies request count linearly while stored bytes stay flat.
Run the three criteria against the published run's own counters:
| Signal | Source counter | Published calibration | What it decides |
| Request density | Requests ÷ TB-months from billing export | 25 requests : 24 objects, roughly 1:1 per pass | Whether request lines can rival storage lines |
| Pass frequency | Pipeline schedule × requests per pass | 61 seconds per logged pass | Linear multiplication of monthly request totals |
| Retry exposure | Failed-request rate in application logs | 0 failures in the logged run | Retries re-bill; error storms inflate the line |
| Compute coupling | CUs consumed per request batch | 0.136 CUs per 25-request run | Agent loops tie compute spend to request volume |
For request-dense, agent-driven estates, this criterion set typically lands in favor of the provider whose included monthly operations absorb the read class; byte-heavy, rarely-touched archives usually justify staying put. Kill the reflex of optimizing the per-gigabyte sticker price first — negotiated storage rates are the smaller lever whenever density goes unmanaged. Before any 2026 migration decision: export thirty days of request-line usage by class, compute your density, and re-run the calculation after every schema change.

Common Mistakes
According to the Aaron Tay substack dated April 29, 2026, the string "S3" appears across the entire fetched source corpus exactly once — inside a CDN image hostname, substack-post-media.s3.amazonaws.com — and never once as a pricing subject. Set that beside the headline share-of-bill range above and you have Pitfall 1 in a single sentence: platform teams routinely quote bill-composition percentages from documents that never priced a single request.
Pitfall 1 — porting someone else's percentage. As How It Works established, request fees are the only bill line that scales with operation count rather than bytes, which means a share-of-bill figure is a fingerprint of a specific workload's GET-to-PUT ratio and object-size distribution. It does not transfer. Before any percentage earns a slot in a migration memo, demand three artifacts from its source: a raw request count, a per-operation unit price, and a bounded billing period. Run that test against the corpus behind this guide and nothing passes — according to the fetched source corpus, no percentage tied to request fees or bill composition appears anywhere in it. Anything missing one of the three artifacts gets relabeled as anecdote, not evidence.
Pitfall 2 — importing compute-unit math into the storage tab. The only concrete unit price in the entire source set is not a request fee at all. According to "AI agent infrastructure stack: from web data to retrieval," a measured run consumed 0.136 compute units, where 1 CU equals 1 GB of memory held for 1 hour, priced at $0.20 per CU. That line prices memory-time, not operations; paste it into an S3-versus-R2 spreadsheet as request spend and the model is wrong by construction. The adjacent trap: the August 5, 2026 Apify walkthrough states that all its cost and latency figures come from measured July 2026 runs of crawl/embed/vector-upsert pipelines, yet the fetched excerpt contains no dollar amounts. "Measured" language without a visible ledger is precisely how phantom precision enters executive decks.
This is also where the old claim that "the conventional approach wastes money on unnecessary steps" dies. The corpus points at the opposite failure mode: teams that treat conventionality itself as the waste skip the counting step, migrate first, and then reproduce the identical operation count on the cheaper provider — because the bill follows the op count, not the vendor name. One representative week of request logs, captured before touching the data plane, is the skipped step that converts the headline range into a number that actually applies to your buckets.
| Source | What it actually contains | Billing-relevant figure | Verdict |
|---|---|---|---|
| Aaron Tay substack (Apr 29, 2026) | "S3" appears once, inside substack-post-media.s3.amazonaws.com | Zero pricing subjects | Reject — no billing content |
| Fetched source corpus (aggregate) | Full-text sweep of all fetched sources | No request-fee percentage anywhere | Reject — no bill-share data |
| Apify blog walkthrough (Aug 5, 2026) | Measured July 2026 crawl/embed/vector-upsert runs | Latency and counters only; no dollar amounts | Partial — latency yes, dollars no |
| "AI agent infrastructure stack" post | Compute metering of one agent run | 0.136 CU × $0.20/CU | Reject for storage tab — compute pricing |
| RAG evaluation cluster (Data AI Hub metrics guide; rank-biased precision paper; query-difficulty paper) | recall@k, MRR, nDCG, golden test sets | No billing lines | Reject — retrieval quality, not fees |
Only one row carries a hard number, and it belongs on the compute tab — that is the explicit winner of this audit, and it wins for the wrong tab. Your next action: before the next architecture review, apply the three-artifact test to every percentage currently in the migration deck, and downgrade each failure to "unverified" in writing. The discipline takes an afternoon; an unpriced assumption in a 500 TB migration case does not.

Insider Tactics
Zero egress is not zero requests. Before touching a rate card, attack the variable that travels with you: operation count. Request fees meter calls, not bytes, so a migration to R2 or GCS swaps the per-call rate while your application keeps issuing the identical call pattern — the request line follows the architecture, not the vendor. Teams that reorder the work (call pattern first, vendor second) arrive at the comparison stage holding a lever no rate card can take away.
The non-obvious strategy: collapse per-object chatter into manifest reads. In most production buckets, request spend concentrates in verbs that move no bytes — HEAD existence probes, paginated LIST sweeps, per-fragment GETs. Each has a structural substitute:
| Access-log signature | Substitute tactic | What it eliminates | Win condition |
|---|---|---|---|
| HEAD probe fired per key before every read | Maintain one manifest object, rewritten on write | Per-key existence chatter | One GET per refresh cycle replaces one probe per key |
| Paginated LIST sweeps over cold prefixes | Consume provider inventory exports as a single object | Page-by-page listing loops | Listing collapses from hundreds of pages to one read |
| Many small fragments fetched together | Bundle into aggregate containers (Parquet, TAR), fan out locally | One GET per fragment | A single bulk request amortizes across the whole set |
| Context object re-fetched every agent turn | Memoize the chunk in memory or local NVMe after first read | Repeated GETs per conversation turn | Second and later turns hit cache, not the bucket |
The caching row deserves emphasis. According to Prof. Tom Yeh's Retrieval Cost lesson (AI by Hand, August 19, 2026), a retrieved chunk is "priced as input, and re-read on every turn after the one that fetched it." His subject is RAG tokens, not storage requests, but the failure mode maps one-to-one: an agent that re-fetches the same context object every turn converts a one-time read into a per-turn tax. Memoize after the first fetch; the second turn should hit memory, never the bucket.
The timing tip: instrument before you negotiate, and time the measurement window. According to the fourteen-document source corpus, no document states any AWS S3 request price — no per-1,000 PUT/GET/LIST rates, no request-fee line item, and no request charge inside any customer bill — and none compares two providers on request fees. Any cross-provider request estimate handed to you is therefore unverified. Manufacture your own evidence: wrap the storage client with per-verb counters (PUT, GET, LIST, HEAD, tagged by bucket) and run them across one full billing cycle that includes a month-end reporting stretch, when read amplification typically peaks. Schedule bundling and manifest-rebuild jobs immediately before heavy read phases, so consolidation cost lands once, ahead of demand rather than during it.
Concrete next action: ship the counter wrapper this sprint. After one cycle you own a verb histogram — the only request-fee forecast in the room that is not a guess — and you can multiply it against whatever rate sheet each vendor produces during the comparison stage above.

Comparison
Normalize every quote to cost per million operations before comparing anything else. Amazon, Cloudflare, and Google publish request pricing in different units and bundle operations differently, so a sticker-rate comparison across S3, R2, and GCS can fail on unit mismatch alone — a per-thousand quote beside a per-million quote describes the same operation with denominators differing by a factor of a thousand. No rate card is reproduced here deliberately: per-operation prices move without much notice, and a table printed in a guide goes stale on arrival. What survives printing is the protocol that produces the numbers.
The side-by-side takes one sitting. Open all three pricing pages and extract six fields per vendor: the mutation-class rate (PUT, COPY, POST, LIST), the read-class rate (GET, HEAD, SELECT), the free monthly allowance and what it scales with, whether LIST bills per call or per key returned, whether storage-class transitions bill as mutations, and whether an egress line exists at all. Reduce every rate to the common per-million denominator, then place your workload on the axis that actually decides this comparison: requests per terabyte-month. Backup archives sit near the floor — write once, read rarely. CDN origins and scan-heavy analytics sit near the ceiling, hammering HEAD and LIST against millions of small keys. The closer you sit to the ceiling, the more the request line converges toward the share of the bill quantified earlier in this guide, and the more the vendor choice matters.
Kill one myth while you're in there: the conventional approach does not waste money on unnecessary steps. The waste runs the other way. Teams that skip the six-field extraction and quote sticker rates from a months-old blog post are the ones overpaying, because free-tier allowances and LIST granularity — the two fields most likely to flip a verdict — are precisely the ones blog summaries omit.
When each option wins, decided explicitly. Egress-heavy fan-out: the zero-egress store wins by construction, since the byte-distance line disappears — though the request line survives untouched, as covered above. Operation-heavy workloads on tiny objects: no vendor wins by default; the free-tier arithmetic decides, and it flips whenever a rate card changes, so re-run it quarterly. Byte-heavy, few-operation archives: nobody wins enough to justify a migration, because request fees are noise at that shape and switching cost exceeds savings. AWS-native estates whose consumers live in the same region: S3 typically wins, because service-to-service traffic inside one region usually never crosses the paid boundary. GCS is the honest open cell — the sources behind this guide contain no verifiable GCS request pricing, so no verdict gets printed here. If your estate is GCP-native, run the same six fields and note that Google groups operations into priced classes; map your hot paths to their class before trusting any total.
| Workload signature | Deciding variable | Winner | Mechanism |
|---|---|---|---|
| Heavy egress to internet or other clouds | Bytes crossing the boundary | R2 | Egress line drops to zero; request line still applies |
| Tiny objects, HEAD/LIST-heavy access | Requests per TB-month | Measured free-tier leader | Allowances differ in size and scaling basis; re-check quarterly |
| Large objects, infrequent reads | Requests per TB-month | Incumbent (usually S3) | Request fees are noise; migration cost exceeds savings |
| AWS-native, same-region consumers | Boundary crossings | S3 | Same-region service-to-service traffic typically stays off the paid path |
| Multi-cloud replication hub | Outbound copy volume | R2 as origin | Fan-out copies stop paying egress at every hop |
Action for this week: pull the three pricing pages, fill the six fields, compute requests per terabyte-month from last month's access logs, and multiply your two normalized rates by that count. Whichever vendor's total is lowest on your actual operation mix — not on a blogger's — is the migration target, and the request line, not the sticker rate, is the number that decides it.
What to do next
| Step | Action | Why it matters |
|---|---|---|
| 1 | Pull the current per-1,000 PUT, GET, and LIST rates off the live Amazon S3 pricing page for each region your 500 TB workload touches. | The 14-document sweep through August 2026 contains no per-1,000 request rate for any provider — this figure is the missing anchor for the entire cost model. |
| 2 | Open Cloudflare's R2 pricing page and record its Class A/B operation rates alongside the zero-egress terms. | R2 appears nowhere in the fetched sources, so the S3-vs-R2 delta remains entirely undocumented until you capture it yourself. |
| 3 | Do the same on Google Cloud Storage's pricing page: Class A/B operation rates plus any free-tier request allowances. | GCS is absent from the corpus too; without its rates the three-way comparison cannot be built at all. |
| 4 | Export one representative month of actual request counts — PUT, GET, HEAD, LIST, COPY, SELECT, and lifecycle transitions — from your AWS billing console or CloudWatch metrics for the 500 TB bucket. | Request fees meter every logged API call regardless of payload size, so real operation counts, not stored bytes, drive the line item. |
| 5 | Multiply your exported counts by the rates from steps 1–3 and divide by the total monthly bill to recompute the request-fee share. | This replaces the unsourced 30–60% working estimate with a derived figure tied to your region, provider, and traffic mix. |
| 6 | Audit read-heavy paths that re-fetch the same object every turn — the mechanic behind the August 19, 2026 lesson where a retrieved chunk is "re-read on every turn after the one that fetched it" — then batch or cache those reads; sanity-check the result against the $0.20 per-unit marker. | Repeated access multiplies per-operation charges even at zero egress, and even a modest per-unit rate compounds into a dominant share once multiplied across a high-volume stream. |
```
Frequently Asked Questions
What share of a large S3 bill can request fees realistically end up taking?
The guide's working estimate places request fees at 30–60% of a 500 TB monthly bill, but that range is unsourced and must be re-derived from current AWS, Cloudflare, and Google pricing pages.
Does the size of an object change what I pay per request?
No — every logged API call (PUT, GET, HEAD, LIST, COPY, DELETE, SELECT) is charged at a per-call rate that ignores whether the payload is 1 KB or 5 GB.
How much does choosing small objects over big ones swing the number of billable events?
Storing the same 500 TB as 1 MiB objects instead of 1 GiB objects creates a 1,000× spread in billable events before lifecycle transitions, versioning purges, or listing scans add anything.
Is a multipart upload billed as just one request?
No — a multi-gigabyte object commonly arrives as hundreds of billable write events, one per part, plus a completion call.
If I scan a huge bucket once, am I charged a single LIST fee?
No — LIST responses are paginated, so enumerating a bucket with hundreds of millions of keys bills per page returned, not per scan.
Do any of the three providers include free request volume before paid rates kick in?
All three meter requests in classes with a monthly zero-rated volume — Cloudflare R2 meters writes and reads as separate classes with included monthly amounts, Google Cloud Storage publishes free-operation tiers, and AWS S3 meters by API call type — but allowance sizes move without announcement, so verify them on each pricing page this quarter.
Quick answers
| If a provider advertises zero egress fees, does that mean storing and accessing objects is free? | No — zero egress is not zero cost, because object stores meter every PUT, GET, LIST, and lifecycle transition separately from stored bytes. |
| What share of a 500 TB monthly bill do request fees represent in the guide's working estimate? | Request fees are estimated at 30–60% of a 500 TB monthly bill, though this range is currently unsourced and must be re-derived from live pricing pages. |
| How does the unit of accounting for request fees differ from storage and egress billing? | Request fees are the only line on an S3-style bill that scales with operation count instead of bytes, so the unit of accounting is the object, not the gigabyte. |
| Why can two teams archiving the same 500 TB land on opposite ends of the request-fee range? | Stored as 1 MiB objects, 500 TB resolves into far more billable objects than the same bytes held as 1 GiB objects — identical bytes with a 1,000× spread in billable events. |
| Which operations bill at higher per-call rates, and which are typically uncharged? | Write-class calls such as uploads, copies, and listings bill at a higher rate than read-class calls like GET and HEAD, while deletes are typically uncharged. |
Also worth reading: Enforcing data-residency policies at the object-storage layer: measured egress cost ($/TB) and P99 latency overhead of S3 Object Lock + bucket policy vs. gateway-side filtering across AWS, Azure Blob, and GCS: Enforcing data-residency policies at the · 2026 SSE-KMS vs Azure SSE vs GCS CSEK: SOC2 & Latency: 2026 SSE-KMS vs Azure SSE · Ceph RGW Audit Logs: Anatomy, Noise Floor, and Filter Selection: Ceph RGW Audit Logs: Anatomy,