# How to Configure Rate Limiting with Free and Pro Tiers in FastAPI Boilerplate

> Learn to configure rate limiting with free and pro tiers in FastAPI Boilerplate. Implement Redis-backed sliding-window counters by defining rules and injecting dependencies.

- Repository: [Benav Labs/fastapi-boilerplate](https://github.com/benavlabs/fastapi-boilerplate)
- Tags: how-to-guide
- Published: 2026-02-26

---

**To configure rate limiting with free and pro tiers in the FastAPI Boilerplate, create tier records in the database, define per-path rate limit rules via the CRUD endpoints, and inject the `rate_limiter_dependency` into your API routes to enforce Redis-backed sliding-window counters automatically.**

The **benavlabs/fastapi-boilerplate** implements a comprehensive, database-driven rate limiting system that supports multiple subscription tiers without requiring code redeployment. This architecture allows you to define granular request limits for different user tiers—such as free and pro—while using Redis for high-performance, distributed enforcement across multiple API workers.

## Understanding the Tier-Aware Rate Limiting Architecture

The system consists of several interconnected components that work together to enforce tier-specific limits dynamically.

### Core Components

- **Tier Model** ([`src/app/models/tier.py`](https://github.com/benavlabs/fastapi-boilerplate/blob/main/src/app/models/tier.py)): Stores subscription levels (e.g., `free`, `pro`) in the `tier` table.
- **Rate Limit Model** ([`src/app/models/rate_limit.py`](https://github.com/benavlabs/fastapi-boilerplate/blob/main/src/app/models/rate_limit.py)): Defines `limit` and `period` values for specific tier-path combinations.
- **Rate Limiter Utility** ([`src/app/core/utils/rate_limit.py`](https://github.com/benavlabs/fastapi-boilerplate/blob/main/src/app/core/utils/rate_limit.py)): A singleton class implementing the sliding-window counter algorithm with Redis.
- **Dependency Injection** ([`src/app/api/dependencies.py`](https://github.com/benavlabs/fastapi-boilerplate/blob/main/src/app/api/dependencies.py)): The `rate_limiter_dependency` function that resolves users, looks up tiers, and enforces limits.
- **Default Configuration** ([`src/app/core/config.py`](https://github.com/benavlabs/fastapi-boilerplate/blob/main/src/app/core/config.py)): Fallback values (`DEFAULT_RATE_LIMIT_LIMIT` and `DEFAULT_RATE_LIMIT_PERIOD`) used when no specific rule exists.

## Setting Up Free and Pro Tiers

Before enforcing limits, you must define your tiers and their corresponding rate rules in the database.

### Creating Tier Records

First, create the tier entries using the admin endpoints. Each tier receives a unique ID used to associate rate limits:

```python

# POST /api/v1/tiers (requires super-user token)

# Create Free tier

{
    "name": "free"
}

# Returns: tier_id = 1

# Create Pro tier  

{
    "name": "pro"
}

# Returns: tier_id = 2

```

### Defining Per-Path Rate Limits

Next, configure specific limits for each tier and endpoint path. The boilerplate allows different limits for the same endpoint based on the user's subscription level:

```python

# Free tier: 10 requests per minute to /api/v1/posts

POST /api/v1/tier/free/rate_limit
{
    "name": "free_posts_minute",
    "path": "/api/v1/posts",
    "limit": 10,
    "period": 60
}

# Free tier: 2 AI generations per hour

POST /api/v1/tier/free/rate_limit
{
    "name": "free_ai_generate", 
    "path": "/api/v1/ai/generate",
    "limit": 2,
    "period": 3600
}

# Pro tier: 60 requests per minute to /api/v1/posts

POST /api/v1/tier/pro/rate_limit
{
    "name": "pro_posts_minute",
    "path": "/api/v1/posts", 
    "limit": 60,
    "period": 60
}

# Pro tier: 50 AI generations per hour

POST /api/v1/tier/pro/rate_limit
{
    "name": "pro_ai_generate",
    "path": "/api/v1/ai/generate",
    "limit": 50,
    "period": 3600
}

```

## Enforcing Rate Limits on API Endpoints

Once tiers and rules are defined, apply rate limiting to your routes using FastAPI's dependency injection system.

### Router-Level Protection

Apply the `rate_limiter_dependency` to an entire router to protect all endpoints within it:

```python
from fastapi import APIRouter, Depends
from app.api.dependencies import rate_limiter_dependency

router = APIRouter(
    prefix="/api/v1/posts",
    dependencies=[Depends(rate_limiter_dependency)]  # Enforces tier-aware limits

)

@router.post("/", response_model=PostRead)
async def create_post(post: PostCreate):
    # Business logic executes only if user hasn't exceeded tier limits

    return await crud_posts.create(db=db, object=post)

```

### Default Limits and Fallback Behavior

When a specific tier-path combination lacks a defined rule in the `rate_limit` table, the system falls back to the default values configured in [`src/app/core/config.py`](https://github.com/benavlabs/fastapi-boilerplate/blob/main/src/app/core/config.py). This ensures all protected endpoints have some level of rate limiting even without explicit configuration.

## How the Rate Limiting Works Under the Hood

When a request hits an endpoint protected by `Depends(rate_limiter_dependency)`, the following workflow executes:

1. **User Resolution**: The dependency obtains the current user or falls back to the client IP address.
2. **Tier Lookup**: It queries `crud_tiers` (defined in [`src/app/crud/crud_tier.py`](https://github.com/benavlabs/fastapi-boilerplate/blob/main/src/app/crud/crud_tier.py)) to load the user's subscription tier.
3. **Rule Retrieval**: It searches `crud_rate_limits` (from [`src/app/crud/crud_rate_limit.py`](https://github.com/benavlabs/fastapi-boilerplate/blob/main/src/app/crud/crud_rate_limit.py)) for a rate limit rule matching the `tier.id` and sanitized request path.
4. **Limit Determination**: If a rule exists, it uses the stored `limit` and `period`; otherwise, it applies `DEFAULT_RATE_LIMIT_LIMIT` and `DEFAULT_RATE_LIMIT_PERIOD` from the configuration.
5. **Redis Counter**: The **RateLimiter** singleton increments a Redis key formatted as `ratelimit:{user_id}:{sanitized_path}:{window_start}` and checks if the counter exceeds the allowed threshold.
6. **Enforcement**: If the counter exceeds the limit, the system raises `RateLimitException`, returning HTTP 429 with a retry-after header. Otherwise, the request proceeds.

## Summary

- **Database-Driven Configuration**: Store tiers in [`src/app/models/tier.py`](https://github.com/benavlabs/fastapi-boilerplate/blob/main/src/app/models/tier.py) and rate limits in [`src/app/models/rate_limit.py`](https://github.com/benavlabs/fastapi-boilerplate/blob/main/src/app/models/rate_limit.py) to enable dynamic updates without redeployment.
- **Redis-Backed Enforcement**: The `RateLimiter` class in [`src/app/core/utils/rate_limit.py`](https://github.com/benavlabs/fastapi-boilerplate/blob/main/src/app/core/utils/rate_limit.py) provides distributed, sliding-window counting using Redis.
- **Dependency Injection**: Use `rate_limiter_dependency` from [`src/app/api/dependencies.py`](https://github.com/benavlabs/fastapi-boilerplate/blob/main/src/app/api/dependencies.py) to protect routes with automatic tier resolution.
- **Flexible Fallbacks**: Default limits in [`src/app/core/config.py`](https://github.com/benavlabs/fastapi-boilerplate/blob/main/src/app/core/config.py) ensure baseline protection when specific rules are undefined.
- **Tier Differentiation**: Configure divergent limits for free and pro users on the same endpoints by creating separate `rate_limit` records for each tier-path pair.

## Frequently Asked Questions

### How do I create new tiers beyond free and pro?

Create additional tiers by posting to the tiers endpoint with any name (e.g., `enterprise`, `basic`). The system in [`src/app/models/tier.py`](https://github.com/benavlabs/fastapi-boilerplate/blob/main/src/app/models/tier.py) supports arbitrary tier names. Once created, assign rate limits to the new tier_id via the rate limit CRUD endpoints just as you would for free or pro tiers.

### What happens if no rate limit rule exists for a specific tier and path?

The `rate_limiter_dependency` falls back to the default values defined in [`src/app/core/config.py`](https://github.com/benavlabs/fastapi-boilerplate/blob/main/src/app/core/config.py): `DEFAULT_RATE_LIMIT_LIMIT` and `DEFAULT_RATE_LIMIT_PERIOD`. This ensures every protected endpoint has rate limiting even without explicit per-path configuration.

### Can I disable rate limiting for specific endpoints?

Yes. Simply omit `Depends(rate_limiter_dependency)` from the endpoint or router definition. Public endpoints without this dependency bypass the Redis counter entirely and allow unlimited requests, regardless of user tier.

### How does the Redis sliding window algorithm work?

The **RateLimiter** utility uses time-windowed counters where the Redis key includes a timestamp bucket (`window_start`) based on the current period. Each request increments the counter for the active window, and the system rejects requests when the count exceeds the configured limit for that tier-path combination.