AI & assistant-friendly summary

This section provides structured content for AI assistants and search engines. You can cite or summarize it when referencing this page.

Summary

S3 storage pricing is genuinely low. S3 request pricing, replication costs, and the compounding effects of versioning and lifecycle misconfiguration are not. Most expensive S3 bills have nothing to do with how much data you store.

Key Facts

  • S3 storage pricing is genuinely low
  • S3 request pricing, replication costs, and the compounding effects of versioning and lifecycle misconfiguration are not
  • Most expensive S3 bills have nothing to do with how much data you store
  • S3 storage pricing is genuinely low
  • S3 request pricing, replication costs, and the compounding effects of versioning and lifecycle misconfiguration are not

Entity Definitions

S3
S3 is an AWS service discussed in this article.

S3 Is Not Cheap — Your Usage Is Expensive

Quick summary: S3 storage pricing is genuinely low. S3 request pricing, replication costs, and the compounding effects of versioning and lifecycle misconfiguration are not. Most expensive S3 bills have nothing to do with how much data you store.

Key Takeaways

  • S3 storage pricing is genuinely low
  • S3 request pricing, replication costs, and the compounding effects of versioning and lifecycle misconfiguration are not
  • Most expensive S3 bills have nothing to do with how much data you store
  • S3 storage pricing is genuinely low
  • S3 request pricing, replication costs, and the compounding effects of versioning and lifecycle misconfiguration are not
S3 Is Not Cheap — Your Usage Is Expensive
Table of Contents

Part 5 of 8: The AWS Cost Trap — Why Your Bill Keeps Surprising You


S3 is the storage substrate of AWS. It stores backups, user uploads, static assets, data lake files, ML training datasets, application artifacts, and everything in between. At fractions of a cent per GB per month for standard storage, it appears essentially free. For many workloads, the storage cost itself is negligible.

The bill comes from how that storage is used, not how much of it exists.

An engineering team storing 50 TB in S3 Standard is paying less than $1,200 per month in storage — genuinely cheap for 50 TB. But if that 50 TB consists of 500 million small files, with a pipeline that lists the bucket to find new files and then fetches them for processing, the request costs from LIST and GET operations can exceed $10,000 per month. The storage is cheap. The access pattern is expensive.

This is the S3 cost trap. It is not about the size of the bucket. It is about the shape of the workload.

Request Pricing: The Invisible Dimension

S3 charges for every API operation against the service. PUT, COPY, POST, and LIST requests are charged at one rate. GET, SELECT, and all other data requests are charged at a lower rate. DELETE and certain lifecycle operations are either free or charged at minimal rates.

The costs feel small per operation — we are talking fractions of a cent per thousand requests. The numbers only become significant at scale. At 10 million GET requests per day, you are spending a meaningful amount monthly on GET requests alone, from a bucket where you might be spending a fraction of that on storage.

LIST operations are the most dangerous. The S3 LIST API returns up to 1,000 objects per call. A pipeline that lists a large prefix to find new files makes one API call per 1,000 objects. A bucket with 100 million objects requires 100,000 LIST calls to enumerate fully. If your pipeline runs this enumeration hourly, you are making 2.4 million LIST calls per day. LIST calls are charged at the PUT/LIST rate, which is higher than GET. The monthly cost of that enumeration alone is material — and the underlying work (scanning a bucket to find new files) is an architectural anti-pattern that S3 Event Notifications or S3 Inventory was designed to replace.

S3 Select and Glacier Instant Retrieval have retrieval charges that are separate from request charges and separate from storage charges. A workflow that queries S3 with S3 Select at high frequency pays per GB of data scanned, not per byte returned. A 1 GB Parquet file with S3 Select returning 10 KB of results still scans 1 GB for billing purposes. If that query runs 10,000 times per day, the scan cost accumulates regardless of how small each result set is.

Glacier Instant Retrieval, Glacier Flexible Retrieval, and S3 Glacier Deep Archive have storage costs far below S3 Standard — but retrieval charges that can exceed the total storage cost for a year if applied to the wrong access pattern. Glacier Deep Archive is designed for data retrieved once or twice per year. A data team that archives data to Glacier Deep Archive and then discovers they need to run retrospective analyses against it pays retrieval charges that quickly make Glacier more expensive than S3 Standard for the same data volume.

The principle: storage class selection must be driven by retrieval frequency, not just storage cost. An analysis of access patterns before tiering data is not optional — it is the decision.

Versioning: The Cost Multiplier Nobody Sees

S3 versioning is a sensible default for production buckets. It protects against accidental deletion, enables point-in-time recovery, and is required by some compliance frameworks. It is also a cost multiplier that many teams activate and then forget to manage.

When versioning is enabled, every PUT to an existing object creates a new version. The previous version is retained. Both versions consume storage. Every lifecycle transition, replication operation, and retrieval fee applies to all versions — not just the current one.

A bucket receiving 1 million object updates per day, with an average object size of 100 KB, generates 100 GB of new version data per day. If no lifecycle policy expires non-current versions, that bucket accumulates 3 TB of version history per month. After a year, the version history is 36 TB — at S3 Standard pricing, not at a discounted rate — because lifecycle policies that transition non-current versions to cheaper storage tiers are a separate configuration that does not apply retroactively.

The lifecycle policy you need if versioning is enabled:

{
  "Rules": [
    {
      "Filter": {},
      "Status": "Enabled",
      "NoncurrentVersionTransitions": [
        {
          "NoncurrentDays": 30,
          "StorageClass": "STANDARD_IA"
        },
        {
          "NoncurrentDays": 90,
          "StorageClass": "GLACIER_IR"
        }
      ],
      "NoncurrentVersionExpiration": {
        "NoncurrentDays": 365
      }
    }
  ]
}

This transitions non-current versions to cheaper tiers and expires them after a year. Without something like this on every versioned bucket, you are paying full S3 Standard rates for years of object history that no engineer is aware of and no process ever reviews.

Delete markers are a related trap. When an object is deleted in a versioned bucket, S3 creates a delete marker rather than removing the object. The previous versions remain and are billed for storage. The bucket appears empty from the console. The costs continue. A bucket that looks empty in the S3 console because all objects have delete markers may still contain terabytes of non-current versions that are generating storage charges.

Cross-Region Replication: Paying Twice for Everything

S3 Cross-Region Replication (CRR) is used for disaster recovery, data residency requirements, and proximity-to-user optimization. It is billed in ways that compose into a higher total cost than most architects anticipate.

When CRR is configured, every new object PUT to the source bucket is replicated to the destination bucket. The charges are: the standard PUT cost to the source bucket, the replication data transfer charge (per GB transferred between regions), the destination PUT request charge (one PUT per replicated object), and the destination storage charge (full storage cost in the destination region for all replicated objects).

If versioning is enabled in both buckets (required for CRR), the version history in both regions is billed. If the destination bucket has its own CRR configured (for a third-region copy), the chain repeats.

Replication filter misconfiguration is a specific failure mode. CRR can be scoped to specific prefixes or object tags. A replication rule scoped to all objects in a bucket replicates everything, including temporary files, intermediate processing artifacts, and test uploads. Engineering teams that use production S3 buckets for ephemeral storage during data processing pipelines often replicate gigabytes of intermediate data that is deleted from the source within hours — but is retained (and billed) in the destination because the delete operation is only replicated if “delete marker replication” is explicitly enabled.

The correct configuration for CRR:

  • Scope replication to specific prefixes (only replicate final output, not intermediate artifacts)
  • Enable delete marker replication if you want deletions to propagate to destination
  • Set lifecycle policies on the destination bucket that mirror the source bucket’s policies
  • Audit monthly what percentage of the destination bucket’s contents are replicated objects that were since deleted from source

The Small Object Problem

S3 charges a minimum billable size for certain storage classes. S3 Standard-IA and S3 One Zone-IA have a minimum billable object size. An object smaller than the minimum is billed as if it were the minimum size. This makes these storage classes economically wrong for small objects.

But even in S3 Standard (no minimum billable size), small objects create an access pattern cost problem. The fixed overhead of an S3 API call — in latency, in billing, in operational overhead — is the same regardless of whether the object is 1 byte or 1 GB. A data lake with tens of billions of 1 KB files pays the same per-request cost as one with files that are 1,000× larger, while gaining 1,000× less data per request. The cost efficiency of the access pattern degrades with object size.

The operational data pattern that creates this problem is writing one file per event: one JSON file per user action, one CSV per transaction, one log file per Lambda invocation. At low volume, this works. At high volume, the bucket becomes difficult to list, expensive to process, and slower to read than equivalent data in larger files.

The fix is compaction. Aggregate small files into larger ones using Glue, EMR, or a Lambda function that runs on a schedule. Target object sizes between 64 MB and 512 MB for data lake objects — this is the range where S3 read efficiency and Athena/Glue/Spark processing efficiency align. The compaction process itself consumes compute and generates API calls, but the reduction in downstream request costs and processing overhead from eliminating small files typically produces net savings at scale.

EBS: The Storage You Forget About

EBS volumes are provisioned and billed by size, not by utilization. A 1 TB gp3 volume bills for 1 TB whether it is 5% full or 95% full. This creates a quiet accumulation problem: instances are terminated, but their root EBS volumes are not deleted if the “Delete on Termination” flag is not set.

The default behavior for EBS volumes attached at launch through most methods sets “Delete on Termination” to true for root volumes. For additional data volumes attached separately, the default is false. A workflow that launches instances with attached data volumes and terminates the instances without explicitly deleting the volumes leaves orphaned EBS volumes running indefinitely at full provisioned cost.

At scale, orphaned EBS volumes represent a measurable fraction of infrastructure costs. A scan of your account using aws ec2 describe-volumes --filters Name=status,Values=available returns all EBS volumes not attached to any instance. “Available” status means the volume is not in use. It is also being charged.

Provisioned IOPS over-provisioning is the other EBS cost failure. io1 and io2 volumes charge separately for provisioned IOPS, independent of actual IOPS consumed. An io2 volume provisioned at 16,000 IOPS for a peak load that never materialized bills for 16,000 IOPS continuously. Migrating to gp3, which provides up to 16,000 IOPS configurable at a lower per-IOPS rate, or right-sizing the provisioned IOPS to actual peak observed usage, reduces this charge significantly.

What to Audit in Your Account

Monthly S3 cost audit:

  • Pull Cost Explorer filtered to S3, grouped by usage type. Identify the top three usage types by spend. For most accounts, one of them will be unexpected.
  • Check the ratio of request costs to storage costs. If requests exceed 30% of total S3 spend, your access patterns warrant review.
  • List all versioned buckets: aws s3api list-buckets | jq -r '.Buckets[].Name' | xargs -I{} aws s3api get-bucket-versioning --bucket {}. For each versioned bucket, check whether a lifecycle policy governing non-current versions exists.

Quarterly EBS audit:

  • aws ec2 describe-volumes --filters Name=status,Values=available for orphaned volumes
  • aws ec2 describe-snapshots --owner-ids self filtered by age for orphaned snapshots (snapshots older than your retention policy with no associated AMI)

S3 Intelligent-Tiering is worth evaluating for buckets where access patterns are unknown or variable. Intelligent-Tiering moves objects between tiers automatically based on access frequency and charges a per-object monitoring fee. For large objects with unpredictable access patterns, the monitoring fee is outweighed by the storage tier savings. For small objects (below the monitoring fee threshold), Intelligent-Tiering does not provide cost benefit and should not be used.

Storage is infrastructure. Like compute, it accrues costs based on configuration, not just consumption. The difference is that compute cost is visible — you see running instances. Storage cost is invisible — you see capacity, not the billing behaviors layered on top of it.


Related reading: AWS Backup Strategies: Automated Data Protection covers backup lifecycle management and cross-region copy costs in operational detail. AWS S3 Security Best Practices: Preventing Data Exposure covers the KMS and versioning configuration that this post discusses from a cost angle. For a foundational cost optimization checklist that includes S3 lifecycle policies, see 5 AWS Cost Optimization Strategies Most Teams Overlook.

Next in the series: Part 6 — Engineering Without Cost Ownership. The organizational and tooling failures that let cost problems grow undetected: delayed billing signals, no cost visibility per team, and the structural gap between the engineers who build infrastructure and the people who see the bill.


The AWS Cost Trap — Full Series

Part 1 — Billing Complexity as a System Problem · Part 2 — Data Transfer Costs · Part 3 — Autoscaling + AI Workloads · Part 4 — Observability & Logging Costs · Part 5 — S3 Storage Cost Traps · Part 6 — The FinOps Gap · Part 7 — Real Failure Patterns · Part 8 — Optimization Playbook

PP
Palaniappan P

AWS Cloud Architect & AI Expert

AWS-certified cloud architect and AI expert with deep expertise in cloud migrations, cost optimization, and generative AI on AWS.

AWS ArchitectureCloud MigrationGenAI on AWSCost OptimizationDevOps

Ready to discuss your AWS strategy?

Our certified architects can help you implement these solutions.

Recommended Reading

Explore All Articles »
Autoscaling Broke Your Budget (AI Made It Worse)

Autoscaling Broke Your Budget (AI Made It Worse)

Autoscaling was supposed to make costs predictable by matching capacity to demand. Instead, it introduced feedback loops, burst amplification, and — with AI workloads — a new class of non-deterministic spend that no scaling policy anticipates.

Logging Yourself Into Bankruptcy

Logging Yourself Into Bankruptcy

Observability is not free, and the industry has collectively underpriced it. CloudWatch log ingestion, metrics explosion, and X-Ray trace volume can together exceed your compute bill — especially once AI workloads introduce high-cardinality telemetry at scale.

Cost Control Is Architecture, Not Discounts

Cost Control Is Architecture, Not Discounts

Savings Plans and Reserved Instances reduce the rate you pay. Architecture determines the volume you pay at. The most durable cost reductions in AWS come from designing systems that structurally generate less spend — not from negotiating a lower price for the same behavior.