The instance you sized against the on-demand hourly rate is rarely what actually shows up as the biggest line on the invoice. Compute is the number everyone budgets against because it's the easiest to estimate up front — pick a vCPU/RAM target, multiply by hours in a month, done. The line items that actually make a bill spiral are the ones nobody sized for in advance, because they don't scale with the thing you were watching: they scale with traffic patterns, forgotten resources, and architectural choices made for reasons that had nothing to do with cost at the time.
Egress: the charge that's invisible until it isn't
Every major provider makes moving data into their cloud free and charges for moving it back out — commonly on the order of several cents per gigabyte to the public internet after a modest free allowance, with the exact rate stepping down at higher volume tiers. That's a rounding error for a typical web application. It stops being a rounding error the moment a workload's actual job is serving large files, streaming media, or running backups that pull data back out for verification — any pattern where output volume is the point of the workload rather than an incidental side effect of it. A service that looked cheap in a proof-of-concept with a handful of test users can have its cost structure completely inverted once egress becomes the dominant line item at real traffic volume, and because egress scales with usage rather than with anything provisioned in advance, it's the cost most likely to still be climbing after everything else has been optimised.
A concrete version of this: a service serving 5TB of downloads a month at a rate on the order of $0.08–0.09/GB works out to somewhere around $400–450 a month in egress alone — often more than the compute instance actually serving those files costs to run. Nobody sizes a budget around that number up front because it isn't visible in a vCPU/RAM sizing exercise at all; it only shows up once real traffic starts flowing, by which point it reads as an unexplained jump rather than a predictable cost that should have been modelled from the start.
NAT gateways: the double charge hiding in the network layer
This is the line item that catches experienced teams off guard, not just beginners, because it's genuinely non-obvious from the architecture diagram. A NAT gateway typically bills two ways at once: a flat hourly charge for the gateway existing at all, and a per-gigabyte data processing charge for every byte that flows through it — and that processing charge is separate from, and in addition to, whatever the underlying data transfer itself already costs. Private subnets are routed through a NAT gateway specifically so their instances can reach the internet without being directly exposed to it, which is correct security architecture — but it means all of that traffic gets taxed twice: once for the NAT gateway processing it, once for the transfer itself. Worse, in some regions and provider configurations, traffic crossing between availability zones on its way to or from the NAT also picks up a cross-AZ data transfer charge, meaning a single request can stack three separate network charges before it ever reaches the internet. None of this shows up as a "compute" or "storage" line — it hides inside networking, which is exactly why it's so often the line item nobody investigated until the bill was already large.
Idle and oversized resources: paying for what you forgot about
Unattached storage volumes left behind after an instance was terminated. Load balancers still running in front of a service that was decommissioned months ago. A development environment sized like production and left running 24/7 because nobody wrote the script to shut it down overnight and on weekends. None of these show up as a spike — they show up as a steady background hum on the bill that's easy to miss precisely because it doesn't change month to month, which is the opposite of how people usually scan a bill for problems (looking for the line that grew, not the line that's just quietly always there). This is also where reserved instances and savings plans, genuinely effective at cutting the sticker price of compute you actually need, can make the problem worse if applied carelessly: committing to a 1- or 3-year term locks in the cost of a resource that was oversized to begin with, turning a fixable inefficiency into a contractual one.
Serverless isn't automatically cheaper at scale
Serverless compute bills in GB-seconds — memory allocated multiplied by execution duration multiplied by invocation count — plus a flat per-request charge, and the generous standard free tier genuinely makes low-to-moderate traffic workloads cost close to nothing. The part that surprises teams later is that this pricing model doesn't asymptote the way reserved compute does: a function running at sustained high volume keeps paying the same per-GB-second rate at request number ten million that it paid at request number one, with no volume discount for being a predictable, constant workload. A steady, high-throughput service is frequently the case where a small reserved or committed-use compute instance ends up cheaper in total than the equivalent serverless function, precisely because reserved pricing is built for exactly that kind of predictability and serverless pricing is built for the opposite — bursty, unpredictable load where paying nothing at zero traffic matters more than getting a volume discount at high traffic.
Reading the bill instead of just paying it
The practical fix for most of this isn't a smarter cost estimate up front — it's tagging every resource with what team, project or environment it belongs to from the moment it's created, so the bill can actually be broken down by something more useful than "everything." Without consistent tagging, a spike is visible in total but untraceable to its cause, which is exactly the situation that turns a one-time investigation into a recurring monthly guessing game. Combined with routine review of unattached volumes, idle load balancers and unused elastic IPs — all of which providers will happily list for you if asked — tagging turns "the bill went up" from a mystery into a specific, attributable line item, which is the actual difference between a cost that gets fixed and one that just gets budgeted around forever.
Budget alerts and anomaly detection, available in some form from every major provider, close the remaining gap: tagging tells you where a cost came from once you've noticed it, but noticing it quickly in the first place is what keeps a misconfigured resource or a runaway process from turning into a full month of unnecessary spend before anyone looks at the invoice. A threshold alert that fires at 20% over the expected monthly run rate is a cheap, low-effort tripwire compared to discovering the same overspend during the next billing cycle's manual review, and it's the one piece of this that requires no ongoing discipline to keep working once it's set up.