How to keep an AI free tier from bankrupting you: two ceilings and a cheap model
An uncapped free tier on an expensive model is how AI apps lose money. Two ceilings keep it safe: a monthly request quota and per-plan model gating.
The fastest way to lose money on an AI product is a generous free tier pointed at an expensive model. Free users have no reason to be frugal and every reason to test your limits, so if your free plan can reach your best model with no ceiling, your worst-case cost per free user is unbounded. A free tier is supposed to be top-of-funnel, not a faucet into your API account. Here is how I make one safe with two independent ceilings and one cheap model.
Ceiling one: a monthly request quota
Every AI route checks the user's usage against their plan limit before doing any model work, and returns HTTP 402 when they are over. That check is the whole enforcement point:
export async function checkQuota(userId: string): Promise<QuotaCheck> {
const plan = await getUserPlan(userId);
const { requests } = await getMonthlyUsage(userId);
return {
ok: requests < plan.monthlyRequestLimit,
plan,
used: requests,
limit: plan.monthlyRequestLimit,
};
}
The free plan's limit is 25 requests per calendar month. The route calls this first; when ok is false it answers 402 instead of calling the model. The count comes from the same per-request usage table that drives billing, so the number the quota reads is the number you actually spent — I wrote up that schema in tracking LLM costs per user.
Ceiling two: a per-minute rate limit
A monthly quota bounds the total, but not the burst. Without a second ceiling, a user could spend the entire month's allowance in ten seconds and hammer your provider with concurrent requests. A separate per-minute rate limiter caps that burst. They defend against different attacks — one bounds the month, the other bounds the second — so you need both, not either.
Gate the model, not just the volume
Volume caps alone are not enough, because 25 requests on your most expensive model is a completely different bill than 25 on your cheapest. So the plan also declares which models it may use, and requests for anything else are clamped to the plan's default:
free: {
monthlyRequestLimit: 25,
allowedModels: ["claude-haiku-4-5"],
defaultModel: "claude-haiku-4-5",
},
A free user who crafts a request asking for Opus does not get Opus — the plan clamps it to Haiku. Model access is a billing decision, enforced in one place, not an if-statement scattered across routes.
The math that makes it safe
Haiku 4.5 bills at 1 dollar per million input tokens and 5 per million output. A chatty free request of roughly 1,000 input and 500 output tokens costs about $0.0035. Twenty-five of them is about nine cents per free user per month. Break-even sits well under 1% conversion — a free tier at that cost is a marketing channel, not a liability.
Now run the same 25 requests against Opus at 25 dollars per million output, with longer answers, and the per-user cost jumps 20 to 50 times — and without the quota, it has no ceiling at all. That gap is the entire argument for gating both volume and model.
Things that bite
- Fail-open versus fail-closed is a real decision. This kit fails open when no database is configured, so the public demo stays usable without setup. In production, a metering outage that silently disables the quota is a spend leak — decide on purpose which way it fails.
- Anonymous users still need an identity. The public demo attributes usage by IP address, so unauthenticated traffic is capped too. Skip that and "free" quietly means "unlimited to anyone not logged in."
- A rate limit is not a quota. One bounds the burst, the other the month. Shipping only one leaves the other door open.
- Cap on requests, keep the tokens. Users understand "25 requests"; bill and reason about margin on the token and cost columns underneath.
Shipwright — the Next.js and Claude starter kit this blog documents — ships this whole safety layer wired together: per-plan quotas, model gating, the per-minute limiter, and the metering that feeds them. You can watch the free tier's cost accrue in real time in the live demo.