Skip to main content
Before you configure anything, you’re deciding two things about your own business. They get decided in the same conversation, which is why they’re easy to conflate — but they’re independent, and keeping them apart will save you a redesign later.

Two separate decisions

What goes in each tier? This is what makes “Free” different from “Pro”, and it’s decided once per tier. What happens when someone wants more than their tier includes? Do they hit a wall and have to upgrade, or do they keep going and pay for the excess? The second one is decided per thing you’re limiting, not per tier — and the answer can be different for every one of them. A single tier can hold something that hard-stops at five, something that keeps serving and charges for the excess, and something that’s simply free forever.
The vocabulary, once: a feature is one thing you might limit or grant. What a tier gives someone for that feature is an entitlement. A plan is the tier itself, and a price is what it costs. Your code checks the entitlement, never the plan name:
  • Bad: if (user.plan === 'pro')
  • Good: if (await kerne.allows('export_pdf', { customer: userId }))

Decision 1: What goes in each tier

The standard “Good-Better-Best” shape: each tier gives more than the one below it, and most of what separates them is either on/off or a number.
  1. Create features: can_access_dashboard, can_invite_members.
  2. Create plans:
    • Free Plan: Includes can_access_dashboard.
    • Pro Plan: Includes can_access_dashboard + can_invite_members.
That’s it for boolean features. A numeric feature (seats, projects, usage) also needs a metering decision — that’s Decision 2, and it’s set per feature, per plan, independently of what else is on that plan.

Decision 2: What happens when someone wants more

For anything you limit by a number, pick what happens once it runs out. Nothing here is “more advanced” than the others — they’re three different answers to the same question, and which one fits depends on what you’re selling, not on how sophisticated your pricing looks.

Option A: Stop there — a hard limit, never billed

Nobody pays their way past this. The plan simply refuses once the allowance is gone. This is not usage-based pricing — nothing is ever charged for going over, because going over isn’t allowed. Right for things a customer should decide to buy more of by upgrading, not discover as a surprise line on an invoice: seats, projects, connected devices.
  1. Create a feature team_seats with type Quota. A seat is a standing count rather than a monthly consumption, so set it to never renew instead of resetting each period.
  2. On the plan, set the allowance to 5 and choose to stop access past it.
  3. Gate the action with consume(), which checks and increments atomically:
Removing a member gives the seat back: kerne.admin.adjustUsage('team_seats', { customer: orgId, delta: -1 }). A counter that never renews is the one place that matters — a per-period quota would have cleared itself anyway.

Option B: Keep going and charge for it — pay-as-you-go past the included amount

The same feature, the opposite choice: past the included amount the customer keeps going and you bill the excess. This is “20/mobase,then20/mo base, then 0.01 per email past 10,000” — genuinely usage-based, unlike Option A.
  1. Open that feature’s cell on the plan and choose to keep serving past the allowance and charge for it.
  2. Write the rate the way you sell it — 0.01 EUR per message, or 5.00 EUR per 1,000 if that’s the quantity you price by. Kerne creates the meter and its price at Stripe; you never leave for the Stripe dashboard and never copy an id back.
  3. Optionally add a spending cap — a ceiling in money. Past it usage still counts and still works, it just stops being billed. Leave it empty for an add-on meant to scale freely.
From there it’s automatic: usage past the included amount reaches the customer’s next invoice with nothing to poll or reconcile. To show them what they’re about to be charged, read their current usage with useUsage. Rates aren’t limited to one number. The quantity you sell by, a schedule of tiers, and whether a tier reprices everything or only its own slice are all part of the same rate — see Usage billing.

Option C: The limit isn’t one pool

Orthogonal to A and B, not a third alternative to them: the customer is one payer, but the thing you meter isn’t one pool — per machine, per project, per seat, per one of their clients. Declare what the feature is counted by, then apply Option A or B on top, and choose whether the allowance and the ceiling are shared across the account or per slice.
“1,000 credits per user, then billed, never past 20 € per user” and “one shared pool of 200 hours, never past 120 € in total” are the same feature with two different plan settings. See per machine, per project, per seat.

Add-ons

A customer holds one live subscription at a time — one payer, one plan. That is enforced in the database, and it is the first thing to know before designing an add-on, because it rules out the shape most people reach for: an add-on is never a second subscription sitting next to the first. It is one of these instead:

A metered feature

Nothing included, a rate, no cap. The customer pays for exactly what they turn on, and it reaches the same invoice. This is the usual answer.

A plan variant

Two plans that differ by one entitlement. Right when the add-on is a lasting choice rather than something toggled.

An override

A negotiated extra on one account, outside the catalog. For deals, not for a product line.
The first covers most add-ons and needs nothing new — it is Option B with an allowance of 0 and the ceiling left empty. Combine it with Option C when the add-on is bought per project or per seat rather than once per account.
Because add-ons ride the subscription rather than sitting beside it, a plan change carries them along: switching plans re-pins entitlements to the new plan, so an add-on that exists on one plan and not the other stops with the switch. Model an add-on you intend to survive a plan change as a feature present on every plan, with a different allowance.

Which shape fits

A quota that gets billed has to restart at zero each period. “Unused allowance carries over” and “bill the excess” together would charge last period’s units again, so the two can’t be combined.