When EC2 instances within a VPC access Amazon S3 in the same region without a Gateway VPC Endpoint, traffic is routed through the public S3 endpoint and incurs standard internet egress charges — even though it remains within the AWS network. This results in unnecessary egress charges, as AWS treats this traffic as data transfer out to the internet, billed under the S3 service.
By contrast, provisioning a Gateway Endpoint for S3 allows traffic between EC2 and S3 to flow over the AWS private backbone at no additional cost. This configuration is especially important for data-intensive applications, such as analytics jobs, backups, or frequent uploads/downloads, where the cumulative data transfer can be substantial.
Because the egress cost is billed under S3, it is often misattributed or overlooked during EC2 or networking reviews, leading to silent overspend.
This inefficiency occurs when small files are stored in S3 storage classes that impose a minimum object size charge, resulting in unnecessary costs. Small files under 128 KB stored in Glacier Instant Retrieval, Standard-IA, or One Zone-IA are billed as if they were 128 KB. If these small files are accessed frequently, S3 Standard may be a better fit. For infrequently accessed small files, transitioning them to archival storage classes like Glacier Flexible Retrieval or Deep Archive can optimize storage spend. Poorly tuned lifecycle policies often allow small files to remain in suboptimal storage classes indefinitely.
Multipart upload allows large files to be uploaded in segments. Each part is stored individually until the upload is finalized by a “CompleteMultipartUpload” request. If this final request is never issued—due to a timeout, crash, failed job, or misconfiguration—the parts remain stored but are effectively useless: they do not form a valid object and cannot be retrieved. Without a lifecycle policy in place to clean up these incomplete uploads, the orphaned parts persist and continue to incur storage charges indefinitely.
ListBucket requests are commonly used to enumerate objects in a bucket, such as by backup systems, scheduled sync jobs, data catalogs, or monitoring tools. When these operations are frequent or target buckets with large object counts, they can generate disproportionately high request charges. In many cases, real-time enumeration is not necessary and can be replaced with more efficient alternatives like S3 Inventory, which provides object metadata on a scheduled basis at lower cost.
S3 buckets often persist after projects complete or when the associated workloads have been retired. If a bucket is no longer being read from or written to—and its contents are not required for compliance, backup, or retention purposes—it represents ongoing cost without delivering value. Many organizations overlook these idle buckets, especially in shared or legacy accounts, leading to unnecessary storage costs over time.
Some S3 lifecycle policies are configured to transition objects from Standard storage to Intelligent-Tiering after a fixed number of days (e.g., 30 days). This creates a delay where objects reside in S3 Standard, incurring higher storage costs without benefit. Since Intelligent-Tiering does not require prior access history and can be used immediately, it is often more efficient to place objects directly into Intelligent-Tiering at the time of upload. Lifecycle transitions introduce unnecessary intermediate costs that can be avoided entirely through configuration changes.
S3 Standard is the default storage class and is often used by default even for data that is rarely accessed. Keeping large volumes of infrequently accessed data in S3 Standard leads to unnecessary costs. Data such as backups, logs, archives, or historical snapshots are often strong candidates for migration to colder tiers like S3 Glacier or Deep Archive. If access patterns are unknown or variable, S3 Intelligent-Tiering can reduce costs without requiring manual transitions.