Article Image

How to manage features & usage limits in your SaaS app with S3

6th April 2022

If you are running a subscription-based SaaS the first order of business will be to integrate with a payments platform like Stripe or Paddle. This is when you will set up your pricing plans on their platform according to your pricing table.

Back in your SaaS app, you will sync those same pricing plans back and associate each plan with features. In a relational database setting, this means creating the following tables at the minimum.

users: Users who have signed up for your app.

subscriptions: Subscription records synced from your payments provider. Each record contains references to a Plan and a User.

plans: Plan records synced from your payments provider. Each record contains an external reference to the plan on your payments provider.

features: These are features of your app such as Seats, Projects, Email Notifications etc.

plan_features: This is used to express a many-to-many relationship between plans and features.

But hang on, how do you deal with what a user is allowed to do on your SaaS app?

How do you ensure that email notifications won’t be sent for Alice on the ‘Hobby’ plan? Or that Bob on the ‘Team’ plan doesn’t create more than 10 projects?

This is when feature toggles and usage limits come into the fray.

Types of SaaS features

Let's introduce three kinds of features commonly found in SaaS apps.

Boolean: These are your standard feature flags. They denote whether a feature is on or off. Eg. you can send out email notifications.

Limit: An absolute limit is set on the usage of a feature. Eg. you can only create 10 projects.

Quota: These are limits in which usage is reset on a periodic basis eg. you can sync insights up to 100 times a day.

Managing usage limits and quotas

Oh but couldn’t I use a feature flagging platform to handle this? Well, yes and no.

A feature flagging and experimentation tool like LaunchDarkly gives you the ability to gate features, and through variations you can even store metadata like integers or JSON to be returned alongside the feature’s state. However, the feature is still very much a boolean — it is either enabled or disabled. You will still have to write code to determine if a user has exceeded their limits or not, decide whether to store usage events, or keep a running count per user.

Hence, we’ll need a solution which unifies feature flagging, usage tracking and policy evaluation in order to bridge the gap.

Essentially it boils down to addressing these subproblems.

Problem 1: We need to check if a User can access a Feature.

Solution: Three-way join on the database, cache the lookup or encode the relationships into an RBAC framework for efficiency.

Problem 2: We need to keep a count of the number of times a User uses a Feature.

Solution: Store the counts somewhere, preferably a database with fast read-write speed, strong consistency and atomic increment / decrement operations. A RDBMS or Redis comes to mind here.

Problem 3: We need to check if a User has exceeded limits on a Feature.

Solution: Middleware / policies on the client and server that checks the User’s usage against the Feature’s limit value.

Problem 4: For quotas, we need to periodically reset the User’s usage count.

Solution: Set up a Cronjob to reset usage at the desired intervals.

Now imagine that your pricing table looks like this:

Modelling such a pricing matrix without having a framework for managing features and usage limits in a scalable, consistent and maintainable manner is a guaranteed recipe for disaster.

System architecture

Here's an idea for a simplified system design that can meet all the above requirements.

At the core of this system design is the use of S3 as the persistence layer. While S3 is commonly thought of as an object store, it is in fact, a huge key-value store. Your data is stored in the form of blobs and accessed via keys i.e. the prefixes to your file. Moreover S3 comes with industry-leading scalability, data availability, security, and performance.

However the killer feature for S3 has got to be it’s strong read-after-write consistency. This means that it is perfectly suitable for keeping track of the usage counters mentioned above. It's essentially a cost-efficient, Redis alternative, albeit with lower read-write performance and a limited access patterns (list, set, put, delete).

With powerful tools such as Athena and Glue at your disposal, you can perform SQL queries directly on the data in S3 or set up ETL workflows to pipe it to a data warehouse.

The trade-off made here is the lost of querying flexibility, as compared to storing the data within the same RDBMS as the rest of your app.

S3 data model

So what kind of data do we need to store on S3?

First is the feature matrix, which is a collections of plans and features and the attributes on these features.

{
"plans": [
{
"plan_id": "Hobby",
"features": [
{
"feature_id": "Seats",
"type": "Boolean",
"value": 1
},
{
"feature_id": "Projects",
"type": "Limit",
"value": 10
},
{
"feature_id": "SyncInsights",
"type": "Daily Limit",
"value": 100
},
{
"feature_id": "CustomerEmails",
"type": "Monthly Limit",
"value": 200
}
]
}
]
}

Secondly, for each user, we can store a map of features to usage counts. We can use the user ID as the object key to achieve O(1) lookups on the S3 bucket.

{
"usage": {
"Seats": 5,
"Projects": 10,
"SyncInsights": 15,
"CustomerEmails": 20
}
}

You can then draw powerful insights from this data: which features do customers use the most or if a particular feature is being underutilized. This enables you to proactively reach out to your customers and course-correct before it's too late. And that's all to it! A simplified usage limit and quota solution that can meet your SaaS product's operational needs.

Should I DIY

At the beginning, hand rolling your own bespoke system for managing features and usage limits may seem like the obvious choice as it is deceptively simple. However, without designing for scale and maintainability from the get-go, tech debt will quickly skyrocket and you’ll find yourself staring down at a tangled mess of spaghetti code.

For solo founders, small teams and startups, who already have plenty on their plates, investing considerable effort to develop such a peripheral system might not be the best use of their time.

Try Limiter today if you are looking for an out of the box usage limits and quota management solution that scales well with you, especially in the cost department.

Sign up for free. No credit card required.