{"course":{"slug":"cloud-and-shipping","title":"Shipping It","url":"https://addaly.com/learn/cloud-and-shipping","level":"intermediate","track":"build"},"lesson":{"slug":"the-bill","title":"The bill, and the traffic that runs it up","url":"https://addaly.com/learn/cloud-and-shipping/the-bill","position":29,"of":74,"minutes":9,"answer":"Alerts tell you the money is gone; only caps, limits and caching stop it leaving.","keyIdea":"Alerts tell you the money is gone; only caps, limits and caching stop it leaving."},"body":{"format":"markdown","text":"## Compute is rarely the surprise\n\nPeople budget for the server. The bills that shock people come from four other places.\n\n**Egress.** Data leaving the cloud. Coming in is free; going out is $0.08 to $0.12 per GB on the large providers. Do the arithmetic once: a 4MB hero image on a page with 500,000 views is 2TB of egress, about $170 to 180 for one image. This is why people move media to Cloudflare R2 or Backblaze B2, which charge nothing for egress. It is the single highest-leverage cost decision in most small projects.\n\n**Per-request pricing with no ceiling.** Serverless bills per invocation and per gigabyte-second. Wonderful at your traffic. Unbounded if something loops.\n\n**Things you forgot are running.** An idle load balancer is roughly $18 a month for doing nothing. A stopped VM still bills for its attached disk. Log ingestion at around $0.50/GB with 90-day retention accumulates quietly. Go and read your line items; there is usually something on there you cannot identify.\n\n**Per-token API calls.** These scale with your users' enthusiasm, and with anyone who discovers an endpoint of yours that does not require an account.\n\n## The three shapes of a shock bill\n\n- **A recursive trigger.** A function writes to a bucket; a write to that bucket triggers the function. This has produced five-figure overnight bills more than once, at real companies.\n- **A retry storm.** Something downstream slows down, clients retry, every retry is another billed invocation, and the retries make the slowdown worse.\n- **Someone else using your endpoint.** An unauthenticated route that calls a paid API is a free paid API for the entire internet, and it will be found by scanners within days of going live.\n\n## Alerts tell you; caps stop it\n\nSet budget alerts: every provider has them. Put one at half of what you can afford and one at the full amount. Then be clear with yourself about what an alert is: **most cloud providers do not offer a hard stop.** The alert is a notification, often delayed by hours, sent to a human who may be asleep. It is a smoke detector, not a sprinkler.\n\nThe sprinklers are the things that act without you:\n\n- Maximum instance count, or maximum concurrency, on your functions.\n- A hard monthly spend limit on the API key at the provider that offers one.\n- A queue with a bounded size in front of expensive work.\n\nPrefer a cap that breaks a feature over an uncapped bill you have to pay in full.\n\n## Rate limits are cost control, not only abuse control\n\nEvery write path, and every path that costs money per call, gets a limit. Three decisions:\n\n**What you key on.** Per-IP is weak: a whole university in Lagos or an office in Manila can share one address, so you punish a crowd; and an abuser rotates addresses for cents. Per-account is stronger. Per-API-key is strongest. Most real systems run both: a loose per-IP limit to blunt the crude stuff, a tight per-identity limit that actually protects the expensive thing.\n\n**The algorithm.** A token bucket is the sensible default: a bucket holds N tokens, refills at R per second, each request takes one. It permits a burst and then enforces a steady rate. Fixed windows have a well-known flaw: send N at 11:59:59 and N at 12:00:00 and you have sent 2N in a second while staying \"within limits\".\n\n**The failure mode.** When the rate limiter itself is unavailable, do you let traffic through or reject it? Fail open on reads, so a limiter outage is not a site outage. Fail closed on expensive or destructive writes. Decide this on a calm afternoon, because otherwise you discover your choice during the incident.\n\nWhen you refuse, return `429` with `Retry-After: 30`. A silent drop or a generic 500 makes well-behaved clients retry harder.\n\n## The cheapest control is caching\n\nA response served from a CDN never reaches your billed compute at all. `Cache-Control: public, max-age=60` on a page that changes about once a minute removes most of your load and most of your bill, and it takes one line."},"check":{"question":"You ship an unauthenticated endpoint that summarises any URL using a paid model, and set a budget alert at $50. Two weeks later the bill is $2,900. The alert email did arrive, on day four. Which change would actually have prevented most of the spend?","options":[{"text":"Requiring an account and applying a per-identity limit, plus a hard spend cap on the model key so spending halts without a human","correct":true},{"text":"Lowering the budget alert to $10 so you find out much sooner","correct":false,"tempting":"Treats the alert as a control. Alerts are delayed and inform a person who may be asleep or on holiday; they never stop anything."},{"text":"Putting the endpoint behind a CDN so repeated requests are served from cache","correct":false,"tempting":"Caching is the right instinct for repeated work, but heavy users send distinct URLs, which is a cache miss on every single call."},{"text":"Moving from per-request serverless to an always-on VM with a fixed monthly price","correct":false,"tempting":"A fixed compute price feels like a ceiling, but the model API bills per token no matter where the code that calls it runs."}]},"prev":{"slug":"tracing-one-slow-request","title":"Finding the slow bit","url":"https://addaly.com/learn/cloud-and-shipping/tracing-one-slow-request"},"next":{"slug":"caching-the-cheapest-server","title":"The request you never serve","url":"https://addaly.com/learn/cloud-and-shipping/caching-the-cheapest-server"},"authorship":"Founder and series editor: Dr Mustafa Mun. Written by AI models to a written standard. Exam keys checked blind by a second model: 3,665 of 3,666 agreed. Academic review invited.","review":{"status":"Draft, open for academic review"},"cite":"Addaly (2026) 'The bill, and the traffic that runs it up', in Shipping It. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/cloud-and-shipping/the-bill (Accessed: 31 October 2026).","licence":{"name":"CC BY-NC-SA 4.0","url":"https://creativecommons.org/licenses/by-nc-sa/4.0/"},"reader":{"schema":1,"title":"The bill, and the traffic that runs it up","courseTitle":"Shipping It","module":{"index":4,"slug":"load-cost-and-abuse","title":"Load, cost and the traffic that is not customers"},"answer":null,"keyIdea":"Alerts tell you the money is gone; only caps, limits and caching stop it leaving.","hero":{"kind":"plate","image":null,"alt":null,"caption":null},"blocks":[{"t":"h2","id":"compute-is-rarely-the-surprise","runs":[{"text":"Compute is rarely the surprise"}]},{"t":"p","runs":[{"text":"People budget for the server. The bills that shock people come from four other places."}]},{"t":"p","runs":[{"text":"Egress.","b":true},{"text":" Data leaving the cloud. Coming in is free; going out is $0.08 to $0.12 per GB on the large providers. Do the arithmetic once: a 4MB hero image on a page with 500,000 views is 2TB of egress, about $170 to 180 for one image. This is why people move media to Cloudflare R2 or Backblaze B2, which charge nothing for egress. It is the single highest-leverage cost decision in most small projects."}]},{"t":"p","runs":[{"text":"Per-request pricing with no ceiling.","b":true},{"text":" Serverless bills per invocation and per gigabyte-second. Wonderful at your traffic. Unbounded if something loops."}]},{"t":"p","runs":[{"text":"Things you forgot are running.","b":true},{"text":" An idle load balancer is roughly $18 a month for doing nothing. A stopped VM still bills for its attached disk. Log ingestion at around $0.50/GB with 90-day retention accumulates quietly. Go and read your line items; there is usually something on there you cannot identify."}]},{"t":"p","runs":[{"text":"Per-token API calls.","b":true},{"text":" These scale with your users’ enthusiasm, and with anyone who discovers an endpoint of yours that does not require an account."}]},{"t":"h2","id":"the-three-shapes-of-a-shock-bill","runs":[{"text":"The three shapes of a shock bill"}]},{"t":"ul","items":[[{"text":"A recursive trigger.","b":true},{"text":" A function writes to a bucket; a write to that bucket triggers the function. This has produced five-figure overnight bills more than once, at real companies."}],[{"text":"A retry storm.","b":true},{"text":" Something downstream slows down, clients retry, every retry is another billed invocation, and the retries make the slowdown worse."}],[{"text":"Someone else using your endpoint.","b":true},{"text":" An unauthenticated route that calls a paid API is a free paid API for the entire internet, and it will be found by scanners within days of going live."}]]},{"t":"h2","id":"alerts-tell-you-caps-stop-it","runs":[{"text":"Alerts tell you; caps stop it"}]},{"t":"p","runs":[{"text":"Set budget alerts: every provider has them. Put one at half of what you can afford and one at the full amount. Then be clear with yourself about what an alert is: "},{"text":"most cloud providers do not offer a hard stop.","b":true},{"text":" The alert is a notification, often delayed by hours, sent to a human who may be asleep. It is a smoke detector, not a sprinkler."}]},{"t":"p","runs":[{"text":"The sprinklers are the things that act without you:"}]},{"t":"ul","items":[[{"text":"Maximum instance count, or maximum concurrency, on your functions."}],[{"text":"A hard monthly spend limit on the API key at the provider that offers one."}],[{"text":"A queue with a bounded size in front of expensive work."}]]},{"t":"p","runs":[{"text":"Prefer a cap that breaks a feature over an uncapped bill you have to pay in full."}]},{"t":"h2","id":"rate-limits-are-cost-control-not-only-abuse-control","runs":[{"text":"Rate limits are cost control, not only abuse control"}]},{"t":"p","runs":[{"text":"Every write path, and every path that costs money per call, gets a limit. Three decisions:"}]},{"t":"p","runs":[{"text":"What you key on.","b":true},{"text":" Per-IP is weak: a whole university in Lagos or an office in Manila can share one address, so you punish a crowd; and an abuser rotates addresses for cents. Per-account is stronger. Per-API-key is strongest. Most real systems run both: a loose per-IP limit to blunt the crude stuff, a tight per-identity limit that actually protects the expensive thing."}]},{"t":"p","runs":[{"text":"The algorithm.","b":true},{"text":" A token bucket is the sensible default: a bucket holds N tokens, refills at R per second, each request takes one. It permits a burst and then enforces a steady rate. Fixed windows have a well-known flaw: send N at 11:59:59 and N at 12:00:00 and you have sent 2N in a second while staying “within limits”."}]},{"t":"p","runs":[{"text":"The failure mode.","b":true},{"text":" When the rate limiter itself is unavailable, do you let traffic through or reject it? Fail open on reads, so a limiter outage is not a site outage. Fail closed on expensive or destructive writes. Decide this on a calm afternoon, because otherwise you discover your choice during the incident."}]},{"t":"p","runs":[{"text":"When you refuse, return "},{"text":"429","code":true},{"text":" with "},{"text":"Retry-After: 30","code":true},{"text":". A silent drop or a generic 500 makes well-behaved clients retry harder."}]},{"t":"h2","id":"the-cheapest-control-is-caching","runs":[{"text":"The cheapest control is caching"}]},{"t":"p","runs":[{"text":"A response served from a CDN never reaches your billed compute at all. "},{"text":"Cache-Control: public, max-age=60","code":true},{"text":" on a page that changes about once a minute removes most of your load and most of your bill, and it takes one line."}]}],"check":{"question":[{"text":"You ship an unauthenticated endpoint that summarises any URL using a paid model, and set a budget alert at $50. Two weeks later the bill is $2,900. The alert email did arrive, on day four. Which change would actually have prevented most of the spend?"}],"options":[{"text":[{"text":"Requiring an account and applying a per-identity limit, plus a hard spend cap on the model key so spending halts without a human"}],"correct":true,"tempting":null},{"text":[{"text":"Lowering the budget alert to $10 so you find out much sooner"}],"correct":false,"tempting":[{"text":"Treats the alert as a control. Alerts are delayed and inform a person who may be asleep or on holiday; they never stop anything."}]},{"text":[{"text":"Putting the endpoint behind a CDN so repeated requests are served from cache"}],"correct":false,"tempting":[{"text":"Caching is the right instinct for repeated work, but heavy users send distinct URLs, which is a cache miss on every single call."}]},{"text":[{"text":"Moving from per-request serverless to an always-on VM with a fixed monthly price"}],"correct":false,"tempting":[{"text":"A fixed compute price feels like a ceiling, but the model API bills per token no matter where the code that calls it runs."}]}],"order":[1,3,2,0],"why":null},"prev":{"slug":"tracing-one-slow-request","title":"Finding the slow bit","minutes":10},"next":{"slug":"caching-the-cheapest-server","title":"The request you never serve","minutes":9}}}