# Vibe Coding and the Surprise Cloud Bill: How to Keep Cost Under Control

*Published 2026-09-25 · Vibe Coding, Cloud Cost, Performance, AI*

> Vibe coding agents call paid APIs in loops, provision oversized infra, and skip caching — quietly running up your bill. How to cap spend before it hurts.

Source: https://www.yashthakur.com/blog/vibe-coding-cost-control

---

**The short answer:** the cost risk in vibe coding is that an agent optimizes for *working*, never for *cheap* — so it happily calls paid APIs in loops, provisions infra sized for a demo that never shrinks, writes N+1 queries, and adds no caps, caching, or rate limits anywhere. The code runs, the bill arrives weeks later, and nobody set an alert. Fix it on day one: put hard budget alerts and spend caps in before you deploy, cache and rate-limit anything billed per call, and right-size infra to your real traffic instead of a guess. Cost control is a design decision, not a cleanup task.

When you vibe code, you review the code for correctness — does it do the thing? — and almost never for cost, because cost isn't visible in the diff. An agent asked to "enrich each user with data from the payments API" will write exactly that: a call per user, every time, forever. It works perfectly in the demo with three users. Then it runs over a 50,000-row table nightly and you've bought 50,000 API calls you didn't need. The agent did what you asked. It just had no idea what it cost.

## Set the ceiling before you deploy, not after

The single highest-leverage thing you can do is boring: turn on a **hard budget alert and a spend cap** on every cloud account and paid API before a single request hits production. Every major provider has them — AWS Budgets, GCP budget alerts, per-key spend limits on most API dashboards. Set a number that would make you wince, wire it to an email or a pager, and for anything that supports a hard cap, use the cap, not just the alert.

This is the difference between finding out on day one and finding out on day thirty. A runaway loop with a cap costs you a capped amount and a page. The same loop without one costs you whatever it can reach before someone happens to look at the dashboard. Agents don't add this — it's not part of "make the feature work" — so it's yours to add every time.

## Cache and rate-limit anything you pay per call

Most surprise API bills come from paying for the same answer repeatedly. The fix is two cheap layers: **cache** results that don't change often, and **rate-limit** so a bug or a bad actor can't run the meter. Here's the shape an agent generates versus the shape you want:

```TS
// ❌ what the agent writes: one paid call per row, every run
async function enrichUsers(users: User[]) {
  const out = [];
  for (const user of users) {
    // billed per call — 50,000 users = 50,000 calls, every night
    const data = await paidApi.lookup(user.email);
    out.push({ ...user, ...data });
  }
  return out;
}

// ✅ cache the stable stuff, batch the rest, cap the blast radius
const cache = new LRU<string, Enrichment>({ max: 100_000, ttl: DAY });

async function enrichUsers(users: User[]) {
  const misses = users.filter((u) => !cache.has(u.email));

  // one batched call instead of N — most paid APIs price batches far lower
  if (misses.length) {
    const fetched = await paidApi.lookupBatch(
      misses.map((u) => u.email),
      { maxBatch: 500 }, // and a rate limiter in front of this client
    );
    for (const row of fetched) cache.set(row.email, row);
  }

  return users.map((u) => ({ ...u, ...cache.get(u.email)! }));
}
```

Same feature, same result. One version pays for every row on every run; the other pays only for what it has never seen and batches even that. The cache turns repeat work into free work, and the rate limiter in front of the client means a retry storm or an infinite loop can't turn into an infinite bill.

## N+1 queries are a cost problem, not just a slow one

The classic N+1 — load a list, then fire one query per item — gets filed under "performance." It's also a cost line. On a managed database you pay for the read capacity, the connections, and often the egress those extra queries burn, and on serverless data platforms you may pay **per request**. A page that does 1 + 200 queries instead of 2 isn't just slower; it's a hundred times the database load for the same screen. Agents produce N+1 constantly because the naive loop is the obvious code. Fix it the obvious way — one query with a join, or a batched `IN (...)` — and watch both the latency and the invoice drop together.

## Right-size infra, and know your scale-to-zero crossover

Agents provision for a demo and leave it: an always-on instance three sizes too big, a managed database tier nobody needed, a cluster for an app with forty users. Match the infrastructure to your **real** traffic, which usually means starting small and letting measured load — not a guess — justify every upgrade.

The serverless-versus-server choice is partly a cost choice, and it has a genuine crossover. Serverless scales to zero and bills per request, so it's cheaper for spiky or low-to-medium traffic — you pay nothing when idle. A steady, high-traffic workload crosses over: past some requests-per-month, a predictable always-on server is cheaper than paying per invocation forever. The mismatch cuts both ways — an always-on server idling at 2% for a spiky workload is money lit on fire, and so is serverless under constant load. Figure out where your traffic sits relative to that crossover before you commit, which is the same traffic-shape question that drives [how to choose a backend you won't regret](/blog/how-to-choose-a-backend) and [architecture by user scale](/blog/architecture-by-user-scale).

## Use agents and skills deliberately

- **A performance-optimization skill** pointed at cost, not just speed — ask it explicitly "what in here calls a paid service per request or per row, and what has no cache?" It will find the N+1s and the uncached hot paths the generalist agent left behind.
- **A backend-architecture skill** to pressure-test infra sizing against real traffic — "what am I over-provisioning for a workload this small, and where's my serverless-vs-server crossover?"
- **A coding-standards skill** to make caps and rate limits a default pattern, so new paid-API calls inherit a budget instead of shipping naked.

The move that de-risks it: have a specialized agent audit the *cost* of the code a generalist agent generated, because the generalist optimizes for "it runs" and never asks "what does it cost at a thousand times this traffic?" That one question, asked before deploy, is the whole game.

A vibe-coded app fails quietly on cost — the demo is cheap, the bill is not, and the gap only shows up once real traffic hits it. Set your caps first, cache and rate-limit everything you pay per call, kill the N+1s, and size infra to reality, and the surprise invoice stops being a surprise.

This is one of the vibe-coding deep-dives — start from [the vibe-coding precautions overview](/blog/vibe-coding-precautions).
