Hidden AWS Costs That Will Surprise You
I have been in IT for thirty years, and I have been working seriously in AWS for most of the last decade. In that time I have watched smart engineers underestimate their AWS bills over and over again, not because they were careless, but because AWS's pricing model has a lot of surface area and some of it is easy to miss.
These are not obscure edge cases. Every item on this list is something I have seen show up as an unexpected line item on a real AWS bill. Some of them are small. A few of them can double your monthly spend if you are not paying attention.
1. NAT Gateway
If you are running private subnets in a VPC (which is the correct, secure way to run production workloads), your instances need a NAT Gateway to reach the internet for things like software updates, API calls, and pulling from package registries.
What most people miss is that NAT Gateway has two separate charges. First, there is an hourly fee of $0.045 per hour, which works out to about $32 per month just for the gateway existing. Second, and this is the one that sneaks up on people, there is a data processing charge of $0.045 per GB for every byte that flows through the gateway.
A multi-AZ setup runs one NAT Gateway per availability zone. Three AZs means three NAT Gateways, $96 per month before a single byte of traffic. Add a few hundred GB of outbound traffic and you are easily looking at $150 or more per month just for NAT.
The fix for some workloads is VPC Endpoints. If your instances are only calling AWS services like S3, DynamoDB, or SQS, you can route that traffic through a VPC Endpoint and bypass the NAT Gateway entirely. S3 and DynamoDB Gateway Endpoints are free. Interface Endpoints cost money but are still often cheaper than routing everything through NAT.
2. Data transfer out to the internet
AWS charges $0.09 per GB for data transferred out to the internet. There is no included allowance, ever. The first byte costs the same as the billionth.
For a typical web application serving a few hundred GB per month this is manageable. For anything that serves large files, video, or high volumes of API responses, this line item grows fast. Four terabytes of egress is $368. That is not a typo, and it is why the cost comparison against VPS providers looks so lopsided when bandwidth is factored in.
CloudFront changes the math significantly. Transferring data from your origin (EC2, S3, ALB) to CloudFront is free. CloudFront to the internet is $0.0085 per GB, which is less than one tenth of the direct EC2 rate. If you are not already fronting your application with CloudFront, the bandwidth savings alone usually justify the setup time.
Also worth knowing: data transfer between AWS services in different regions is not free. Cross-region traffic is $0.02 per GB. If your architecture sends data between us-east-1 and us-west-2 at any volume, that adds up.
3. Idle RDS instances
RDS does not have a pause button. If you are running a development or staging database on RDS and it is not actively being used, it is still accruing charges at full price. A db.t3.medium runs about $60 per month. A db.r6g.large runs over $200. Neither of them care whether you ran a single query this month.
This is one of the most common sources of waste I see in AWS accounts with more than a handful of engineers. Someone spins up an RDS instance for a project, the project ends or goes quiet, and the database sits there for months generating charges that nobody notices because they are small enough individually but significant in aggregate.
The practical fix is Aurora Serverless v2, which scales to zero when idle and only charges for the capacity you actually use. For dev and staging environments that are not running 24 hours a day it is almost always cheaper. For production workloads with consistent traffic, provisioned RDS is usually still the better choice.
At minimum, run a monthly audit of your RDS instances. AWS Cost Explorer makes this straightforward. Any instance with near-zero database connections for more than a few weeks is a candidate for shutdown or replacement.
4. Elastic IPs you forgot about
Since February 2024, every public IPv4 address in your AWS account costs $0.005 per hour, whether it is attached to a running instance or sitting idle. That is $3.60 per month per address, which sounds trivial until you discover that someone on your team spun up ten instances for load testing six months ago, terminated the instances, and left the Elastic IPs sitting there. What makes this worse than it used to be: even attached IPs now cost money. People who thought they were fine because their instances were running are getting surprised too.
Run this periodically to find unattached Elastic IPs in your account:
aws ec2 describe-addresses --query 'Addresses[?AssociationId==null]'
Any address without an AssociationId is costing you money right now. Release the ones you do not need.
5. CloudWatch Logs retention
By default, CloudWatch Logs never expire. Every Lambda function, ECS container, EC2 instance with the CloudWatch agent, and AWS service that writes logs will keep adding to your log storage indefinitely unless you configure a retention policy.
CloudWatch Logs storage costs $0.03 per GB per month. That seems cheap, but a busy application can generate gigabytes of logs per day. A high-volume Lambda function or an ECS service with verbose logging can accumulate hundreds of GB of logs over a year without anyone noticing.
The fix takes five minutes. Go to CloudWatch, select each log group, and set a retention period. 30 days is reasonable for most application logs. 7 days is fine for debug-level logs you only need during active development. Some compliance requirements need 90 days or longer, but unless you have a specific reason to keep logs forever, do not.
Ingestion is also not free: $0.50 per GB for custom logs ingested into CloudWatch. High-volume logging architectures should consider routing logs to S3 directly (much cheaper for storage) and using Athena to query them when needed.
6. EBS snapshots accumulating silently
EBS snapshots cost $0.05 per GB per month. A single snapshot of a 500 GB volume is $25 per month. If you have automated snapshot policies running daily on a fleet of instances and nothing is cleaning up the old ones, the cost compounds quickly.
The specific scenario I have seen cause the most grief: a team sets up an automated snapshot policy, later terminates the EC2 instances (perhaps migrating to containers), but never removes the snapshot policy. The snapshots keep running against the now-deleted volumes, specifically against the last state of those volumes. The charges keep accumulating because no one is looking at that account anymore.
AWS Data Lifecycle Manager handles snapshot cleanup automatically. If you are taking automated snapshots, configure a retention count or age limit at the same time. Also worth running periodically: look for snapshots whose source volume no longer exists. Those are almost always safe to delete.
7. Load balancers running with no traffic
An Application Load Balancer costs $0.0225 per hour just to exist: about $16.43 per month before a single request. On top of that, LCU (Load Balancer Capacity Unit) charges of $0.008 per LCU-hour accrue based on traffic volume. The base charge is not enormous, but it is a fixed cost that continues whether or not anything is hitting the load balancer.
The situation that causes problems: a staging environment gets stood up with its own ALB for realistic testing, the sprint ends, the EC2 instances get terminated, but the load balancer is left running. Nobody notices the $16 per month because it is a rounding error on a large account. Multiply that by ten forgotten staging environments and it is nearly $2,000 per year.
If you are running load balancers for non-production environments, consider using a single shared ALB with host-based or path-based routing rules to serve multiple environments. It is a bit more configuration upfront and significantly less waste over time.
The pattern behind all of these
Every item on this list has the same root cause. AWS makes it very easy to provision resources and very easy to forget about them. The billing model charges for existence, not just usage, and the individual costs are small enough that they fly under the radar until someone sits down and actually looks at the full bill line by line.
The practical defense is a monthly Cost Explorer review. Set a budget alert in AWS Budgets so you get an email when spend crosses a threshold you define. And when you terminate a resource, take 60 seconds to look at what it was connected to: Elastic IPs, snapshots, load balancers, NAT Gateways, log groups. Cleaning those up at the same time costs nothing and prevents the slow creep of forgotten charges.
If you are at the stage of evaluating whether AWS is the right platform for your workload in the first place, the calculator below gives you an honest comparison of what the same specs would cost across AWS, DigitalOcean, Vultr, and Linode. The bandwidth and storage costs are included, not just the instance price.
Pricing figures in this article reflect AWS rates as of April 2026 in the us-east-1 region. Prices vary by region and change periodically. Always verify on the AWS pricing page before making infrastructure decisions.