Bootstrapped Home · Feature Upvote · Scribbleton Personal Wiki · Thermostat NPS

How Checkly manages plans & features in their SaaS app


When getting started with my SaaS I found plenty of advice on marketing, pricing, and positioning, but not so much technical info to help with the building.

Tim Nolet from Checkly encountered the same problem, so decided he’d add the missing content to his blog:

How do you deal with what a user can do on their account in a SaaS app? Can Jane on the “Starter” plan create another widget when she is near the limit of her plan? What if she’s a trial user?

Turns out this is a mix of things

  • Feature toggling
  • Counting stuff™
  • Custom API middleware very specific to your situation

Like the topic of our last post in this series on creating a basic SaaS data model there is a lack of clear examples on how to deal with this super common problem.

Read the whole post here.

BTW: I found answers to many technical problems by posting and asking on the Bootstrapped forum!



All pretty standard stuff, IMHO.

I’d add that a trial is not exactly a boolean. When a trial is getting closer to expire, you may want to increase the number of reminders to the user. Hence the trial is more like “days left until trial expires” value. This also lets to tune a trial’s length individually for different prospects.

Also, re: DB schema for a plan. It is OKish, but in addition to a FK to a standard plain one may want to have a number of override fields. E.g. the plan has 100 calls, but you promised this particular customer 300 calls. So you link him to 100 calls plan but set the value of CALLS_OVERRIDE to 300 instead of default NULL. The query shouldn’t become more complex because of course, you read the plan via a VIEW, not table, so this and any other future complexity is hidden.



In a sense, all our plans are custom. You can convert any plan to any plan at any time by enabling or disabling properties.


  • number of records - number
  • number of tenants - number
  • number of schedules - number
  • available types of schedules - enum
  • connector enabled - boolean
  • plugin enabled - boolean
  • feature enabled - boolean

Additionally, for “number” properties we set the warning/enforced flag.

The properties are key/value pairs stored within the account, with the ability to add new properties at will.

There is no “plan” table but there are templates.

The trial plan equals to the default “Business” plan, except there is a soft expiration date and we are not enforcing the number of records.

There is a twist. Our “Enterprise” plan implies a dedicated instance so, there is an extra step.

1 Like


The one item there that isn’t spoken about that much generally is feature flagging and its power for rollout strategy.

Its particularly pertinent only when you have a number of paying customers and you roll out a new feature where for example:

  1. you’d like only the new customers from a certain date to receive that feature
  2. you’d like to roll a feature to only a certain subset of customers
  3. you’d like to experiment - some customers get to see a certain feature, some don’t perhaps based on a set of personal parameters or just at random
  4. feature gating - perhaps you have an enterprise plan which offers a feature nobody else has!

There are a couple of tools for this -, etc
Some build it themselves which if you scale to hundreds of customers/employees becomes a bad idea.

Do you use feature flagging @SteveMcLeod?



That reminds me the enterprise billing and such systems, where each feature and trait has its own code, and the plan is essentially a set of codes. There are unbelievably complex rules for which codes can come with which; codes have activation and expiration dates; can have subcodes etc etc etc.

Geezus, it is complicated. Very flexible, tho. There are practically no plan situation which you cannot express with those rules - or create a new one in the rule editor.

There must be a SaaS for that. Host other people’s plans. Provide an easy UI to edit standard plans and users’ plans. Provide an API for plan query and update. Charge users. Deal with expired CCs. Maintain subscriptions.

This is almost like a payment processor, but it also manages the plans.

But it would probably fail - the biggest cost center for the aforementioned enterprise systems is the troubleshooting when a plan is expected to do X, but it doesn’t. Now you have to debug the rules, which is very time consuming = expensive.



Yes, but infrequently. When I want to initially release a new feature only to a few customers, I use a feature flag. I have a “feature_flag” table in my database, but after reading the article I’m considering a denormalised field in the “customer” table.

On occasion, I’ve done something much worse - I’ve hard-coded an “if company_id = x then” statement to make something available to only a specific customer. I know, I know, this is not the right way!

Why and when I’ve done this would make a cautionary tale of trying to run a software company while travelling.

1 Like


Thanks for the link to the checkly blog. Quite interesting.



Code rules are pain even if done “right”. Just recently I’ve found that my “grace period is over” check is triggered even if the license is valid. A typo in a validation routine. As the result, the UI refused to make any changes some two months after the personal license activation.

(I’m 90% sure that the next post will be from Wyatt :D).

I’m idly considering now that an instance should get the license state with all dates (trial end, grace end) calculated and all flags set from the server, so I can fix that logic on the server ASAP if required. However, my app instances are behind firewalls so that option is not available.

1 Like


This is something that I would never do in my past days as a corporate developer, guarding the sanctity of my code, unless really pressed by management, and then I hated it. But when you run your own business you get a different perspective on these things. It’s quite often useful, or even necessary, to implement quick&dirty solution asap, and deal with technical debt later on. And you learn that cheap hacks are sometimes good enough and can solve things for years and that no one would care. Of course, you can’t let it ruin stability or performance of your software, but if maintainability is the only thing that suffers, you can pay that price later. Good thing is you don’t have to convince management that it’s necessary to spend some time clean up things when you reach that point.

1 Like