S3 request cost surprise: when API calls beat storage on the bill
S3 charges per request, not just per GB stored, so a workload making millions of small GET, PUT, or LIST calls can pay more for requests than for storage. Here is why it happens and how to cut request cost.
Quick answer
S3 bills per request in addition to per GB stored: GET, PUT, LIST, and other operations each have a per-request price (writes and LISTs cost more than reads). Workloads that make millions of small requests, chatty applications, many tiny objects, frequent LIST operations, or high-rate logging, can pay more for requests than for the storage itself. The surprise is that a bucket holding little data can still cost a lot if it is hammered with requests. Cut it by batching, caching, using fewer larger objects, and avoiding needless LIST calls.
People think of S3 cost as a storage bill, priced per GB, and are surprised when the request charges dwarf it. S3 charges for every API operation, and at high request rates those per-request fees add up fast, sometimes exceeding the storage cost entirely. A bucket with little data but millions of requests can be a genuine bill surprise, and it is entirely avoidable once you see it.
How S3 request pricing works
| Operation | Relative cost |
|---|---|
| GET / read | Cheaper, per thousand requests |
| PUT / COPY / POST / write | More expensive per request |
| LIST | Priced like writes, more than reads |
Each S3 operation has a per-request price, typically quoted per thousand requests. Reads (GET) are cheaper; writes (PUT, COPY, POST) and LIST operations cost more per request. The charge is tiny per call, which is exactly why it hides: nobody notices a fraction of a cent, until an application makes hundreds of millions of calls a month and the total becomes one of the larger lines on the bill.
What drives the surprise
Common causes: applications that read and write many small objects one at a time, high-rate logging or event data written as individual objects, frequent LIST calls to enumerate buckets (especially large buckets, which cost more to list), and polling patterns that hammer S3 repeatedly. Storing many tiny objects is doubly bad, more requests to write and read them, and more overhead. It is a classic member of the unexpected charges family.
Cutting request cost
Batch operations and combine many small objects into fewer larger ones, which cuts both write and read requests. Cache frequently-read objects (via CloudFront or an application cache) so repeated reads do not hit S3 every time. Avoid unnecessary LIST calls by tracking object keys in a database or index instead of enumerating the bucket. Aggregate high-rate events before writing rather than one object per event. Each reduces the request count directly, which is where the cost lives.
Keeping it in check
Watch request metrics alongside storage, since the request line can grow independently of how much data you hold. Design access patterns for fewer, larger operations from the start, and combine this with lifecycle policies and the right storage class for a full S3 cost picture, noting that some cheaper storage classes have higher per-request and retrieval fees. Price your S3 usage against the resource catalog so request cost is part of the plan, not a surprise.
FAQ
Why is my S3 request cost so high?
Because S3 charges per API request in addition to per GB stored, and workloads that make millions of small requests, chatty applications, many tiny objects, frequent LIST operations, or high-rate logging, accumulate large per-request charges. The charge is tiny per call, so it hides until the volume is huge. A bucket with little data but millions of requests can cost more for requests than for storage.
How does S3 request pricing work?
Each operation has a per-request price, typically quoted per thousand requests. Reads (GET) are cheaper, while writes (PUT, COPY, POST) and LIST operations cost more per request. The per-call charge is a fraction of a cent, which is why it goes unnoticed until an application makes hundreds of millions of calls a month, at which point the request total becomes a significant line on the bill.
Can S3 requests cost more than storage?
Yes. For request-heavy workloads with relatively little data, the per-request charges can exceed the per-GB storage cost entirely. A bucket holding a small amount of data but hammered with millions of GET, PUT, or LIST calls pays more for the API operations than for the storage. This is the surprise that catches teams thinking of S3 purely as a storage bill.
How do I reduce S3 request cost?
Batch operations and combine many small objects into fewer larger ones to cut both write and read requests, cache frequently-read objects via a CDN or application cache so repeated reads do not hit S3, avoid unnecessary LIST calls by tracking object keys in a database or index, and aggregate high-rate events before writing rather than one object per event. Each reduces the request count where the cost lives.
Why are many small objects expensive in S3?
Because each object requires its own requests to write and read, so storing data as many tiny objects multiplies the per-request charges compared to fewer larger objects holding the same data. LIST operations over buckets with huge object counts also cost more. Combining small objects into larger ones, or aggregating events before writing, cuts the request count and the associated cost significantly.
How does C3X help with S3 request cost?
C3X prices your S3 usage from Terraform before you deploy, helping surface the cost model, including request charges, so an access pattern that would generate heavy request volume is considered at design time. That complements runtime monitoring by making the full S3 cost picture, storage, requests, and retrieval, part of the plan rather than a surprise discovered on the bill.
What to do next
Account for S3 request cost before you deploy. C3X reads your Terraform and prices your resources against a live catalog. Start with the quickstart.
Share this post
Try C3X on your own Terraform
Free and open source. No API key required. One command to install, one command to estimate.