# API Rate Limiting: A Complete Guide for Developers

> Source: <https://dev.to/avijitbera/api-rate-limiting-a-complete-guide-for-developers-pna>
> Published: 2026-08-12 01:31:42+00:00

APIs are the foundation of modern applications. Whether you're building a SaaS platform, mobile application, AI product, or public developer API, your backend can receive thousands or even millions of requests every day.

But what happens when one user sends too many requests?

Without proper controls, excessive API traffic can cause:

**API rate limiting** is one of the most effective ways to control API traffic and protect backend infrastructure.

In this guide, we'll explain **what API rate limiting is, how it works, common rate limiting algorithms, HTTP 429 responses, different rate limiting strategies, implementation approaches, best practices, and how an edge API gateway can simplify rate limiting.**

**API rate limiting** is a technique used to control how many requests a client can make to an API within a specific period.

For example, an API might allow:

```
100 requests per minute per API key
```

If a client exceeds the limit, the API can temporarily reject additional requests.

A simple flow looks like this:

```
Client
   │
   │ Request
   ▼
API Gateway
   │
   ├── Check rate limit
   │
   ├── Within limit? ─── Yes ──► Backend API
   │
   └── Limit exceeded? ── No ──► HTTP 429
```

The purpose isn't necessarily to prevent users from making requests.

Instead, rate limiting ensures that **API resources are used within defined boundaries**.

Imagine you have an API endpoint:

```
POST /api/login
```

A normal user might make a few requests.

But an attacker could send thousands of requests per second:

```
Request 1
Request 2
Request 3
...
Request 100,000
```

If every request reaches your application, your backend has to process all of them.

That can result in:

```
High traffic
     ↓
More application processing
     ↓
More database queries
     ↓
Higher CPU / memory usage
     ↓
Slower API responses
     ↓
Possible outage
```

With rate limiting:

```
100,000 requests
       ↓
Rate Limiter
       ↓
Allowed requests → Backend
Blocked requests  → HTTP 429
```

The backend receives only the traffic it is designed to handle.

API rate limiting is useful for several different problems.

Public APIs can be abused by automated scripts, bots, crawlers, or malicious users.

Rate limits make excessive usage more difficult.

Every API request consumes resources.

Depending on your application, a request may require:

Rate limiting helps prevent a sudden increase in traffic from overwhelming these resources.

Authentication endpoints are particularly important.

For example:

```
POST /api/login
```

Without rate limiting, an attacker could repeatedly attempt passwords.

You could apply a stricter policy:

```
Login:
5 requests / minute / IP
```

while allowing a less sensitive endpoint:

```
Products:
300 requests / minute / IP
```

More API requests can mean higher infrastructure costs.

This is especially important when your API calls expensive services such as:

Rate limiting can help prevent unexpected traffic from generating unexpected bills.

Suppose you have 1,000 customers.

Without rate limits, one customer could potentially consume most of your API capacity.

With customer-level limits:

```
Customer A → 10,000 requests/hour
Customer B → 10,000 requests/hour
Customer C → 10,000 requests/hour
```

resources can be distributed more predictably.

At its simplest, a rate limiter keeps track of requests associated with a client.

For example:

```
API Key: abc123

Requests:
10:00:01 → 1
10:00:05 → 2
10:00:12 → 3
10:00:20 → 4
...
```

The rate limiter compares the request count against a configured limit.

For example:

```
Limit: 100 requests / minute

Current usage: 73

73 < 100
      ↓
Request allowed
```

When the limit is exceeded:

```
Limit: 100 requests / minute

Current usage: 101

101 > 100
       ↓
Request rejected
       ↓
HTTP 429 Too Many Requests
```

When a client exceeds an API rate limit, the standard HTTP status code is:

```
429 Too Many Requests
```

For example:

```
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 30
```

The response could contain:

```
{
  "error": "rate_limit_exceeded",
  "message": "Too many requests",
  "retryAfter": 30
}
```

The `Retry-After`

header can tell the client how long it should wait before trying again.

This allows well-designed clients to automatically back off instead of continuously retrying.

There isn't one universal rate limiting algorithm.

Several approaches are commonly used.

The most important ones are:

Let's look at each one.

The **fixed window algorithm** divides time into fixed intervals.

For example:

```
Limit:
100 requests / minute
```

The system creates windows:

```
10:00:00 ───────── 10:01:00
10:01:00 ───────── 10:02:00
10:02:00 ───────── 10:03:00
```

Each window gets its own request counter.

For example:

```
10:00 window
Requests: 73

73 < 100
Allowed
```

Once the counter reaches 100:

```
Requests: 101

101 > 100
Blocked
```

When the next minute starts, the counter resets.

The biggest problem is the **boundary burst**.

Imagine:

```
10:00:59 → 100 requests
10:01:00 → 100 requests
```

A client could potentially send 200 requests in approximately one second while technically staying within both windows.

This is called the **fixed-window boundary problem**.

A sliding window doesn't reset at fixed boundaries.

Instead, it continuously looks backward over a specific period.

For example:

```
Limit:
100 requests in the last 60 seconds
```

At 10:01:30, the system checks requests between:

```
10:00:30 → 10:01:30
```

At 10:01:31, it checks:

```
10:00:31 → 10:01:31
```

The window continuously moves forward.

A sliding window counter provides a compromise between fixed windows and fully timestamp-based sliding windows.

Instead of storing every request timestamp, the system uses counters from multiple windows and calculates an approximate current usage.

This reduces memory usage while providing smoother rate limiting than a simple fixed window.

It can be useful for high-volume APIs where exact timestamp tracking isn't necessary.

The **token bucket** algorithm is one of the most popular approaches for API rate limiting.

Imagine a bucket that holds tokens.

Each API request consumes one token.

For example:

```
Bucket capacity: 100 tokens
Refill rate:     10 tokens/second
```

Initially:

```
[● ● ● ● ● ● ● ● ● ● ...]
100 tokens
```

A request consumes a token:

```
Request
   ↓
Consume 1 token
   ↓
99 tokens remaining
```

Tokens are continuously added back at the configured refill rate.

This means clients can often handle short bursts while still respecting a long-term average rate.

Suppose:

```
Bucket capacity = 100
Refill rate = 10 tokens/second
```

A client can make a short burst of requests as long as tokens are available.

Once the bucket is empty:

```
No tokens
   ↓
Request rejected
   ↓
HTTP 429
```

The leaky bucket algorithm processes requests at a controlled rate.

Imagine requests entering a bucket:

```
Requests
 ↓ ↓ ↓ ↓ ↓
┌─────────────┐
│   Bucket    │
│             │
└──────┬──────┘
       │
       ▼
   Controlled
     output
```

Requests are processed at a relatively consistent rate.

If the bucket becomes full, additional requests are rejected or dropped.

This makes the algorithm useful when you want to smooth traffic rather than allow large bursts.

The two algorithms are related but behave differently.

| Feature | Token Bucket | Leaky Bucket |
|---|---|---|
| Allows bursts | Yes | Limited |
| Smooths traffic | Moderate | Strong |
| Common API use | Very common | Common |
| Flexible | High | Moderate |
| Request processing | Based on tokens | Based on output rate |

A token bucket is often a good choice when an API needs to support legitimate short bursts.

A leaky bucket is useful when maintaining a more predictable request-processing rate is important.

Choosing the algorithm is only part of the problem.

You also need to decide **what should be rate limited**.

The simplest strategy is limiting requests by IP address.

For example:

```
100 requests/minute/IP
```

This is useful for public APIs and unauthenticated endpoints.

However, IP-based limits aren't perfect.

Many users can share the same public IP through:

Therefore, an IP address shouldn't always be treated as an individual user.

For developer APIs, API-key-based rate limiting is often more accurate.

For example:

```
API Key A → 1,000 requests/hour
API Key B → 10,000 requests/hour
API Key C → 100,000 requests/hour
```

This also makes it easier to create different limits for different subscription plans.

For example:

```
Free
1,000 requests/month

Pro
100,000 requests/month

Enterprise
10,000,000 requests/month
```

Authenticated applications can rate limit based on user identity.

For example:

```
User ID: 12345
Limit: 500 requests/hour
```

This can provide better fairness than IP-based rate limiting.

Not every API endpoint has the same cost.

For example:

```
GET /products
500 requests/minute

POST /orders
100 requests/minute

POST /login
10 requests/minute

POST /generate-ai
20 requests/minute
```

Endpoint-specific limits are often more effective than one global limit.

SaaS applications frequently implement tier-based rate limits.

For example:

| Plan | Requests/minute | Monthly Requests |
|---|---|---|
| Free | 20 | 10,000 |
| Pro | 200 | 1,000,000 |
| Business | 1,000 | 10,000,000 |
| Enterprise | Custom | Custom |

This makes rate limiting part of the product's usage model.

A robust API often needs multiple layers of rate limiting.

For example:

```
Global limit:
100,000 requests/minute

        +

Per API key:
1,000 requests/minute

        +

Per IP:
100 requests/minute

        +

Endpoint:
POST /login → 10 requests/minute
```

This creates multiple protection layers.

If one user starts abusing the API, they can be blocked without necessarily affecting everyone else.

There are several places where you can implement API rate limiting.

For example:

```
Client
  ↓
Node.js / NestJS
  ↓
Rate limiter
  ↓
Database
```

The request has already reached your infrastructure.

If thousands of malicious requests arrive, your application still has to process them before rejecting them.

You can implement rate limiting at the load-balancer layer.

```
Client
  ↓
Load Balancer
  ↓
Rate Limit
  ↓
Application
```

This moves traffic control earlier in the request path.

An API gateway is often a natural location for rate limiting.

```
Client
  ↓
API Gateway
  ├── Authentication
  ├── WAF
  ├── Rate Limiting
  ├── Caching
  └── Routing
       ↓
Backend
```

The advantage is that multiple backend services can share the same rate limiting policies.

An edge API gateway can enforce rate limits before requests travel to your origin.

```
User
  ↓
Nearest Edge
  ↓
Rate Limiter
  ↓
Allowed?
  │
  ├── No → HTTP 429
  │
  └── Yes
       ↓
    Origin API
```

This can significantly reduce unnecessary origin traffic.

For APIs with large public traffic volumes, enforcing limits at the edge can be particularly useful.

Rate limiting becomes more complicated when your API runs on multiple servers.

Imagine:

```
                 API Gateway
                     │
          ┌──────────┼──────────┐
          ▼          ▼          ▼
       Server A   Server B   Server C
```

If each server keeps its own counter, you could accidentally allow more requests than intended.

For example:

```
Limit = 100 requests/minute

Server A → 100
Server B → 100
Server C → 100

Total → 300 requests
```

The intended limit was 100, but 300 requests were allowed.

This is why distributed rate limiting often requires a shared state system.

Common technologies include:

Redis is frequently used for distributed rate limiting because it provides fast in-memory operations.

A simplified architecture:

```
              API Gateway
                   │
                   ▼
               Rate Limiter
                   │
                   ▼
                 Redis
                   │
                   ▼
                Counter
                   │
             ┌─────┴─────┐
             │            │
          Allowed       Blocked
             │            │
             ▼            ▼
          Backend       HTTP 429
```

A key might look like:

```
rate_limit:user:12345
```

or:

```
rate_limit:ip:203.0.113.10
```

The counter can expire automatically after the configured time window.

A well-designed API should communicate rate limit information to clients.

Common headers include:

```
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 27
X-RateLimit-Reset: 1723456789
```

When the limit is exceeded:

```
HTTP/1.1 429 Too Many Requests
Retry-After: 30
```

Header naming conventions can vary between APIs, so consistency and clear documentation are more important than a particular custom header name.

A client shouldn't continuously retry immediately after receiving HTTP 429.

Bad behavior:

```
429
 ↓
Retry
 ↓
429
 ↓
Retry
 ↓
429
 ↓
Retry
```

This can make the situation worse.

Instead, clients should use **backoff**.

For example:

```
Request
  ↓
429
  ↓
Wait
  ↓
Retry
  ↓
429
  ↓
Wait longer
  ↓
Retry
```

A common strategy is **exponential backoff with jitter**.

For example:

```
1 second
2 seconds
4 seconds
8 seconds
16 seconds
```

Random jitter can be added so that many clients don't retry simultaneously.

Different endpoints have different costs.

A database-heavy endpoint should usually have a different limit from a lightweight endpoint.

Use the standard:

```
429 Too Many Requests
```

when the client exceeds the configured request rate.

Use `Retry-After`

where appropriate.

This makes your API easier to consume.

Developers should know:

Poorly documented rate limits can lead to frustrating API integrations.

Depending on your API, consider combining:

```
IP
API Key
User
Endpoint
Organization
Subscription Plan
```

For example:

```
GET /health
→ 1,000 req/min

GET /products
→ 500 req/min

POST /generate
→ 20 req/min
```

The limits should reflect the actual resource cost.

IP addresses can represent many users.

For authenticated APIs, API keys, user IDs, or organization IDs often provide more meaningful rate limiting identities.

Track:

This can help distinguish legitimate growth from abuse.

Rate limiting isn't a complete security solution.

For public APIs, consider combining:

```
DDoS protection
      +
WAF
      +
Authentication
      +
Rate limiting
      +
Bot detection
      +
Monitoring
```

The terms **rate limiting** and **throttling** are sometimes used interchangeably, but they can describe slightly different behaviors.

Sets a maximum number of requests that can be accepted during a period.

```
100 requests/minute
```

Can refer more broadly to controlling or slowing traffic when a threshold is reached.

For example:

```
Normal traffic
      ↓
High traffic
      ↓
Slow processing
      ↓
Extreme traffic
      ↓
Reject requests
```

The exact terminology depends on the API platform.

Rate limits and quotas solve different problems.

Controls **how quickly** requests can be made.

```
100 requests/minute
```

Controls **how many requests** can be consumed over a longer period.

```
1,000,000 requests/month
```

You can use both:

```
Per minute:
1,000 requests

Per month:
10 million requests
```

This is common in SaaS and developer API pricing.

Rate limiting is particularly important for AI applications.

An AI request may consume significantly more resources than a normal API request.

For example:

```
GET /products
→ inexpensive

POST /generate
→ model inference
→ expensive
```

An AI platform might therefore use several limits:

```
Requests/minute
Tokens/minute
Tokens/day
Requests/day
Monthly usage
```

For example:

```
Free:
10 requests/minute
100,000 tokens/month

Pro:
100 requests/minute
5,000,000 tokens/month
```

AI APIs often need both **request-based limits and usage-based quotas**.

Webhooks can also benefit from rate limiting.

Imagine a third-party service sends:

```
10,000 webhook events
```

within a few seconds.

Your webhook endpoint may become overloaded.

A gateway can help control the traffic before it reaches your application:

```
Webhook Provider
       │
       ▼
API Gateway
       │
       ├── Rate Limit
       ├── WAF
       ├── Validation
       └── Queue / Routing
       │
       ▼
Webhook Service
```

This is particularly useful for SaaS platforms that receive high-volume events.

Managing rate limiting independently in every backend service can become difficult as your infrastructure grows.

[EdgeWrap](https://app.edgewrap.pro) provides an edge API gateway layer that can sit in front of your existing APIs.

Instead of implementing traffic controls independently across multiple services:

```
Client
  │
  ├────► User API
  │
  ├────► Order API
  │
  └────► Payment API
```

you can put a gateway in front:

```
                    Client
                      │
                      ▼
                ┌───────────┐
                │  EdgeWrap │
                │           │
                │    WAF    │
                │ Rate Limit│
                │   Cache   │
                │  Routing  │
                └─────┬─────┘
                      │
          ┌───────────┼───────────┐
          ▼           ▼           ▼
       User API    Order API   Payment API
```

This allows rate limiting and other API policies to be managed at a centralized layer.

You can configure your gateway through the [EdgeWrap dashboard](https://app.edgewrap.pro) and use the [EdgeWrap documentation](https://docs.edgewrap.pro/) for configuration and implementation details.

A production API might use multiple controls:

```
                         Internet
                            │
                            ▼
                    ┌───────────────┐
                    │    EdgeWrap   │
                    │               │
                    │ DDoS          │
                    │ WAF           │
                    │ Bot Detection │
                    │               │
                    │ Rate Limiting │
                    │               │
                    │ Cache         │
                    │               │
                    │ Analytics     │
                    └───────┬───────┘
                            │
                            ▼
                     ┌─────────────┐
                     │ API Gateway │
                     └──────┬──────┘
                            │
              ┌─────────────┼─────────────┐
              ▼             ▼             ▼
          Service A      Service B      Service C
              │             │             │
              └─────────────┼─────────────┘
                            ▼
                         Database
```

The important architectural principle is to reject unnecessary traffic **as early as possible**.

If a request can be safely rejected at the edge, there's little reason to send it through your application servers and database.

There is no universal value such as:

```
100 requests/minute
```

that works for every API.

Instead, consider:

How expensive is the request?

How many requests can your infrastructure safely process?

How frequently do legitimate users make requests?

Do users naturally send bursts?

Should different customers have different limits?

Could the endpoint be targeted by attackers?

For example:

```
                    Suggested Policy

Health Check       → High limit
Product Listing    → Medium/High
Search             → Medium
Login              → Low
Password Reset     → Very Low
AI Generation      → Low + Token Quota
Payment            → Low + Authentication
```

The best rate limit is based on your application's actual behavior and capacity.

If legitimate clients frequently receive HTTP 429 responses, your API becomes difficult to use.

A limit that doesn't meaningfully protect your infrastructure isn't useful.

This still consumes backend resources.

For high-risk public APIs, earlier enforcement can be more effective.

Shared networks can cause legitimate users to affect each other.

Developers need to know how to handle HTTP 429 responses.

Per-server counters can produce incorrect global limits when traffic is distributed across multiple servers.

You need visibility into why requests are being blocked.

Otherwise, it's difficult to distinguish abuse from legitimate traffic growth.

Before deploying an API, consider this checklist:

```
☐ Define limits per endpoint
☐ Choose a rate limiting algorithm
☐ Decide what identifies a client
☐ Configure burst behavior
☐ Return HTTP 429
☐ Consider Retry-After
☐ Document limits
☐ Monitor rate-limit events
☐ Protect authentication endpoints
☐ Protect expensive operations
☐ Consider distributed rate limiting
☐ Combine rate limiting with WAF/DDoS protection
☐ Review limits as traffic grows
```

API rate limiting controls how many requests a client can make to an API during a specific period. It helps prevent abuse, protect backend infrastructure, control costs, and ensure fair resource usage.

The API typically returns the HTTP `429 Too Many Requests`

status code. The response may also include a `Retry-After`

header indicating when the client should try again.

There is no single best algorithm. Fixed windows are simple, sliding windows provide smoother control, and token buckets are useful when you need to support controlled bursts.

It depends on your application. IP-based limits work well for unauthenticated traffic, while API-key or user-based limits are often more appropriate for authenticated developer APIs.

Rate limiting can help reduce abusive traffic, but it should not be considered a complete DDoS protection solution. Large-scale DDoS attacks generally require dedicated edge-level mitigation.

Yes. By preventing excessive requests from reaching your backend or expensive third-party services, rate limiting can help control infrastructure and API usage costs.

Rate limiting controls the speed of requests, such as 100 requests per minute. A quota controls total usage over a longer period, such as 1 million requests per month.

Rate limiting can be implemented inside your application, at a load balancer, API gateway, or edge layer. For protecting origin infrastructure, enforcing limits closer to the edge can prevent unnecessary requests from reaching your backend.

API rate limiting is a fundamental part of building reliable and secure APIs.

A good rate limiting strategy helps you:

The most effective implementations usually combine several controls:

```
                 API Protection
                       │
       ┌───────────────┼────────────────┐
       ▼               ▼                ▼
  Authentication   Rate Limiting       WAF
       │               │                │
       └───────────────┼────────────────┘
                       ▼
                 DDoS Protection
                       │
                       ▼
                    Caching
                       │
                       ▼
                    Backend
```

As your API grows, implementing rate limiting directly inside every service can become difficult to maintain. A centralized API gateway can move these concerns into a dedicated infrastructure layer.

If you want to manage API traffic at the edge, [EdgeWrap](https://app.edgewrap.pro) provides a managed API gateway with rate limiting alongside security, caching, routing, reliability, and API observability features. You can learn more about configuring it in the [EdgeWrap documentation](https://docs.edgewrap.pro/).
