Serverless cost traps and how to dodge them
Serverless promises you only pay for what you use. The fine print is that 'what you use' includes a few expensive surprises. Here are the traps we design around so your bill stays small.
Serverless is one of the best tools we have for keeping infrastructure right-sized. You pay for execution, not idle capacity, and it scales to zero when nobody’s around. For a lot of products — especially ones with spiky or unpredictable traffic — it’s exactly right.
But “pay only for what you use” hides a sharp edge: what you use can quietly include things you didn’t intend to. Here are the traps we design around so the promise actually holds.
Trap 1: Over-provisioned memory
Lambda bills on memory × duration. The instinct is to give a function plenty of memory “to be safe.” The catch is that you pay for that headroom on every single invocation, forever.
The dodge: measure, don’t guess. We profile real invocations and right-size memory to the actual peak plus a sane margin. Sometimes raising memory is cheaper, because more memory also means more CPU, so the function finishes faster and the duration drops more than the memory rate rises. You can’t reason about this from the armchair — you tune it against real numbers.
Trap 2: The chatty function
Serverless makes it trivially easy to call out to other services. So functions start making one database call, then another, then a third API request — each one billing duration while the function sits there waiting on the network.
You’re paying premium compute rates to do nothing but hold the line open.
The dodge: collapse round-trips. Batch queries, fetch in parallel instead of in sequence, and push filtering into the database instead of pulling rows out to filter in code. A function that finishes in 40ms instead of 400ms costs a tenth as much — and the user gets their answer faster too.
Trap 3: NAT Gateway, the silent meter
This one catches almost everyone. Put a Lambda in a VPC so it can reach a private database, let it also call the public internet, and traffic routes through a NAT Gateway — which bills per hour and per gigabyte processed. We’ve seen NAT charges quietly become the single largest line on an otherwise tidy serverless bill.
The most expensive cloud costs are the ones nobody decided to spend. They accrete from defaults.
The dodge: use VPC endpoints to reach AWS services (S3, DynamoDB, and friends) without touching the NAT at all, and architect so functions that need the public internet aren’t needlessly trapped behind a gateway. It’s an architectural decision, not a setting you flip later.
Trap 4: Logs you’ll never read
Verbose logging on a high-traffic function generates a torrent of CloudWatch data — ingested and stored, both metered. Months later you’re paying to retain gigabytes of console.log("here") nobody will ever open.
The dodge: log at the right level, sample the noisy paths, and set retention policies so logs expire instead of accumulating into a permanent tax.
The pattern underneath
Every one of these traps is the same shape: a sensible default, left unexamined, quietly metering in the background. Serverless doesn’t make you wasteful — it makes waste invisible, because there’s no idle server sitting there to remind you it exists.
That’s why we treat cost as an architecture decision, made at design time, not a cleanup job for later. Right-sized memory, collapsed round-trips, deliberate networking, disciplined logs. None of it is exotic. It’s just the difference between a serverless bill that delivers on the promise — and one that surprises you in the worst way at the end of the quarter.