Technology

API Rate Limiting: A Practical Guide for Small SaaS Teams

Every API needs rate limiting eventually, but most small teams either bolt it on badly after an incident or build something far more complicated than the problem deserves. Here is the version I actually build.

API Rate Limiting: A Practical Guide for Small SaaS Teams

API rate limiting is one of those things that nearly every SaaS product needs and almost nobody builds until something has already gone wrong. I have lost count of the number of times a client has come to me after a single misbehaving integration partner has hammered their API and taken the whole platform down for every other customer at the same time. It is a completely avoidable problem, and the fix is usually simpler than people expect.

I have built rate limiting into APIs for CampSuite, for client Dynamics 365 integrations, and for a good few consulting projects over the years. The pattern that actually works for a small team is almost never the one that shows up first in a Google search, because most of the writing on this subject is aimed at engineers at companies with a platform team, not a founder trying to ship a product with three developers.

Why Small Teams Get This Wrong

There are two failure modes I see constantly, and they sit at opposite ends of the spectrum. The first is ignoring rate limiting entirely until an incident forces the issue, which usually means building it under pressure at 11pm with a customer's production system on fire. The second, and this one annoys me more, is reading about token buckets, sliding windows and distributed rate limiting with Redis clusters, and building something that would only make sense at ten thousand requests a second when the actual API does ten a second on a busy day.

Both mistakes come from the same root cause. Nobody has actually sat down and worked out what problem rate limiting is solving for their specific product, so the decision gets made reactively instead of deliberately. That is the same trap I have written about before when it comes to small teams reaching for microservices before they need them. The tooling exists for a scale you are probably not at yet.

What Rate Limiting Is Actually For

Strip away the buzzwords and rate limiting exists to solve three distinct problems, and they are not the same problem even though people talk about them as if they are.

Protecting Shared Infrastructure

This is the big one for multi tenant SaaS products. One customer's integration going rogue, whether through a bug, a bad retry loop, or genuinely heavy usage, should never be able to degrade the experience for every other customer sharing the same database and application servers. This is a fairness problem first and a security problem second.

Controlling Cost

If your API calls out to anything metered, whether that is a third party data provider, an AI model, or Azure compute that scales with load, an unlimited API is an unlimited bill waiting to happen. I have seen this bite Dynamics 365 integrations hard, where a poorly built connector polls an endpoint every few seconds instead of using webhooks, and the client only notices when the Azure invoice arrives.

Enforcing Your Pricing Model

If you sell API access as part of a tiered product, rate limits are how you actually enforce the tiers rather than relying on customers behaving themselves. This one is commercial as much as technical, and it is worth designing your limits around your pricing page rather than the other way round.

A Simple Approach That Actually Works

For the vast majority of small SaaS products, a fixed window or sliding window counter per API key, held in whatever cache or datastore you already run, is genuinely enough. You do not need a dedicated rate limiting service. You do not need Redis if you do not already have Redis for something else. Track a request count against a key and a time window, reject or queue requests once the count is exceeded, and return a clear response so the calling application can back off properly.

The part people skip, and the part that actually matters more than the algorithm, is the response you send back. Return a proper 429 status code, include a Retry After header, and put the limit and remaining count in the response headers so well built client applications can self throttle. Half the value of rate limiting disappears if the caller has no idea why their request just failed.

Where To Put It

Put rate limiting as close to the edge as you reasonably can. If you run behind Azure API Management, Cloudflare, or any API gateway, use its built in throttling policies before you write a single line of custom code. I default to this on every project now, because it means the limiting happens before a request touches your application servers or your database, which is exactly where you want the protection to sit. Only build it into application code when your gateway genuinely cannot express the rule you need, such as limits that vary by subscription tier stored in your own database.

What Happens When You Get It Wrong

I have seen a support team spend an entire day trying to diagnose why a system was running slowly for everyone, only to eventually trace it back to one customer's script hammering an unthrottled endpoint every second. No error, no warning, just a slow creeping degradation that looked like a database problem until someone actually checked the request logs. Rate limiting would have turned that into a single rejected request and a support ticket, rather than a platform wide incident.

The other failure I see less often but which is more embarrassing is limits set so aggressively, usually copied from a blog post rather than based on actual usage data, that a legitimate customer gets throttled during completely normal use. Look at your actual traffic patterns before picking numbers. Set limits generous enough that no genuine customer notices them, and tight enough that a runaway script gets caught quickly.

My Honest Take

Rate limiting is boring infrastructure, and boring infrastructure is exactly the kind of thing that gets skipped by small teams focused on shipping features, which I understand completely because I have done it myself. But it is cheap to build early and genuinely painful to bolt on after a customer has already been hurt by its absence. Build the simple version now, using whatever data store you already have, put it behind your gateway if you have one, and move on. You can always make it more sophisticated later if you ever actually reach the scale that needs it, which is rarer than most engineering blogs would have you believe.

If you are building out API infrastructure for a SaaS product and want a second opinion on where to draw these lines, this is exactly the kind of practical architecture decision I help clients work through in development consulting. It is also the sort of unglamorous but essential groundwork I cover in The 28 Day Startup, because the businesses that survive tend to be the ones that get the boring parts right early rather than the ones with the cleverest code.

More from the blog

Technology7 min read

Why Microservices Are Wrong for Most Small SaaS Products

Read more
Technology6 min read

Azure Cost Optimisation for Small Business: Where the Money Actually Goes

Read more
Dynamics 3657 min read

Dynamics 365 Integration Patterns That Actually Hold Up

Read more