cd /news/developer-tools/how-to-put-a-hard-daily-cap-on-your-… · home topics developer-tools article
[ARTICLE · art-82787] src=dev.to ↗ pub= topic=developer-tools verified=true sentiment=· neutral

How to put a hard daily cap on your LangChain.js API costs

Developer Kim Beomgyu has released budget-guard, an open-source circuit breaker that enforces hard daily dollar caps on LLM API spending, with a LangChain.js adapter that integrates via a single callback handler. The tool converts real token usage to USD, splits cached and reasoning tokens, and throws a BudgetExceededError before a request leaves the process, preventing runaway loops from racking up costs. It supports per-feature tracking and offers Redis and file stores for shared or ephemeral caps.

read2 min views6 publishedAug 1, 2026

If an agent decides how many API calls to make, your cost ceiling is whatever the agent feels like today. Most days that's fine. The day a tool errors out and the chain retries its way around it, it isn't, and nothing in your logs will look wrong while it happens.

I maintain budget-guard, a small open source circuit breaker for LLM API bills. It has a LangChain.js adapter, and the whole integration is one callback handler:

import { ChatOpenAI } from '@langchain/openai';
import { BudgetGuardHandler } from 'budget-guard/langchain';

const handler = new BudgetGuardHandler({
  project: 'my-app',
  dailyCapUSD: 25,
  model: 'gpt-4o',
  feature: 'support-bot',
});

const model = new ChatOpenAI({ model: 'gpt-4o' });
await model.invoke(messages, { callbacks: [handler] });

That's the entire setup. Before each model call, the handler checks what the project has spent today. Under the cap, the call goes through and its real token usage is converted to USD and added to the running total. Over the cap, it throws a BudgetExceededError

before the request leaves your process, so a runaway loop dies on the first blocked call instead of the hundredth.

Some details that matter in practice.

The cap is in dollars, not tokens. Tokens stopped being a useful unit once cached input and reasoning tokens got their own prices. One "token" can bill at four different rates inside a single response. The handler reads usage_metadata

(falling back to llmOutput.tokenUsage

on older code paths), splits cached input from uncached, counts reasoning tokens where the provider bills them separately, and prices each part.

The feature tag is the part I would not skip. A single daily total tells you that you have a problem. A per-feature breakdown tells you where. In my case the leak was an enrichment job nobody had thought about in weeks, quietly sitting at 60% of total spend.

Blocking works because the handler sets raiseError internally. LangChain swallows callback errors by default, which would turn the cap into a polite suggestion. Nothing to configure here, but it is worth knowing why the throw actually stops the chain.

It is process-local by default. The default store resets when your process restarts. There is a Redis store so a whole worker fleet shares one cap (with an atomic reserve-then-settle path, so a hundred concurrent calls can't race past the limit together), and a file store for cron jobs that only live for seconds.

And what it deliberately doesn't do: it is not a gateway, there is no dashboard, and it cannot see calls that don't go through it. It is the breaker in your fuse box, not the power company. If you already run a full LLM observability platform, you probably don't need this. If you have one Node app and a nervous feeling about your usage page, it's npm i budget-guard

and the five lines above.

The lessons that led to building it are in an earlier post: 7 things I learned trying to stop LLM API bills from silently exploding.

── more in #developer-tools 4 stories · sorted by recency
── more on @kim beomgyu 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/how-to-put-a-hard-da…] indexed:0 read:2min 2026-08-01 ·