limits is a Python library for rate limiting via multiple strategies with commonly used storage backends such as Redis, Memcached, MongoDB, and Valkey. It provides identical APIs for use in synchronous and asynchronous codebases, enabling robust control over request rates. The library maintains an active development status with regular releases, with version 5.8.0 being the latest stable release at the time of verification.
Install & Compatibility
Where this runs
tested against v5.8.0 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.9150 runs
installs and imports cleanly · install 0.0s · import 0.407s · 20.3MB
glibcpy 3.10–3.9150 runs
installs and imports cleanly · install 2.2s · import 0.369s · 21MB
18MB installed
● package 18MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
strategies
✓ from limits import strategies
storage
✓ from limits import storage
RateLimitItem
✓ from limits import RateLimitItem
RateLimitExceeded
✓ from limits.errors import RateLimitExceeded
✗ from limits.errors import LimitedError
`LimitedError` is from `throttled-py` library, `RateLimitExceeded` is for `limits`.
parse
✓ from limits import parse
parse_many
✓ from limits import parse_many
This quickstart demonstrates how to set up a simple rate limit using in-memory storage. It defines a rate limit, initializes a fixed-window rate limiter, and then simulates multiple actions for a user, demonstrating how the `test` and `hit` methods interact with `RateLimitExceeded` exceptions. It also shows how to get remaining quota and reset time.
from limits import parse, strategies, storage, RateLimitExceeded
import time
import os
# 1. Initialize a storage backend
# For simplicity, using in-memory storage. For production, use Redis/Memcached.
# A Redis example:
# REDIS_URL = os.environ.get('REDIS_URL', 'redis://localhost:6379')
# store = storage.RedisStorage(REDIS_URL)
store = storage.MemoryStorage()
# 2. Define a rate limit (e.g., 5 requests per minute)
# parse() converts a string like '5/minute' into a RateLimitItem
rate_limit_string = '5/minute'
rate_limit = parse(rate_limit_string)
# 3. Initialize a rate limiter strategy
# FixedWindowRateLimiter is a common strategy
limiter = strategies.FixedWindowRateLimiter(store)
def do_limited_action(user_id):
try:
# 4. Test the limit for a specific identifier (e.g., user_id)
if limiter.test(rate_limit, user_id):
# 5. Consume the limit (i.e., record a hit)
limiter.hit(rate_limit, user_id)
print(f"[{user_id}] Action performed at {time.strftime('%H:%M:%S')}. Remaining: {limiter.get_remaining(rate_limit, user_id)}")
else:
raise RateLimitExceeded(rate_limit)
except RateLimitExceeded as e:
# Query available capacity and reset time
remaining = limiter.get_remaining(e.limit, user_id)
reset_at = limiter.get_reset_time(e.limit, user_id)
print(f"[{user_id}] Rate limit exceeded for {e.limit}. Try again in {reset_at - time.time():.1f} seconds. Remaining: {remaining}")
# Simulate some requests
user = "test_user_1"
print(f"--- Simulating requests for {user} ({rate_limit_string}) ---")
for i in range(7):
do_limited_action(user)
time.sleep(1) # Simulate some delay
print("\n--- Waiting for reset time ---")
time.sleep(60)
print("\n--- Simulating requests after reset ---")
for i in range(3):
do_limited_action(user)
time.sleep(1)
limits --version
Debug
Known issues
breakingVersion 5.0.0 introduced several backward-incompatible changes, including dropping support for the `Fixed Window with Elastic Expiry` strategy and the `etcd` storage backend. Additionally, the default implementation for `async+memcached` was changed from `emcache` to `memcachio`.fixReview your application's rate limiting strategies and storage configurations. If using `Fixed Window with Elastic Expiry` or `etcd`, migrate to an alternative strategy/storage. If using `async+memcached`, ensure `memcachio` is compatible or manually configure `emcache` if preferred and still supported via an extra.
affects: >=5.0.0
gotchaUsing `MemoryStorage` (the default in basic examples) in a multi-process or distributed environment will not provide a global rate limit. Each process will have its own independent rate counter, which can lead to limits being exceeded across the entire system.fixFor production or distributed applications, configure a shared storage backend such as Redis, Memcached, or MongoDB. These backends enable centralized rate limit tracking across multiple application instances.
affects: All
gotchaWhen migrating from `limits` versions prior to 5.6.0, note that project metadata moved to `pyproject.toml` and the project now uses `hatch` for package builds. While this primarily affects contributors, it's worth noting for build system interactions.fixFor development or build automation, ensure your tooling is compatible with `pyproject.toml` and `hatch`. Direct users are generally unaffected unless they interact with the build system.
affects: <5.6.0 to >=5.6.0
deprecatedOlder versions of `limits` (e.g., prior to v2.7.0 and v2.4.0) had specific requirements for `redis` and `coredis` versions. While current versions relax these, always verify compatibility.fixAlways check the `limits` library's `requires` and `Provides-Extra` on PyPI or the `pyproject.toml` for the most up-to-date dependency compatibility, especially when upgrading or installing specific optional backends.
affects: <2.7.0
Errors
Common errors & fixes
ModuleNotFoundError: No module named 'limits'
The 'limits' library is not installed in your Python environment or is not accessible via the Python path.
fixInstall the library using pip: `pip install limits`
ConfigurationError: redis library is not available
The specified storage backend (Redis in this case) requires its corresponding Python client library to be installed, which is missing, or the connection URI is invalid/unreachable.
fixInstall the necessary backend client (e.g., `pip install redis` for Redis) and ensure your connection URI is correct and the server is accessible.
limits.errors.RateLimitExceeded: 5 per 1 minute
The configured rate limit for a specific operation or endpoint has been exceeded, preventing further execution until the limit resets.
fixThis is an expected behavior of rate limiting. To handle it gracefully, catch the `RateLimitExceeded` exception and implement retry logic, inform the user to wait, or adjust your application's request rate. For example, `try: ... except RateLimitExceeded: print('Rate limit hit, please wait.')` TypeError: 'Rate' object is not callable
This error can occur if you attempt to call a `Rate` object directly as a function, rather than using it as an argument for rate limiting functions or decorators.
fixEnsure you are passing the `Rate` object to the appropriate `limits` function or decorator (e.g., `limiter.hit(rate)`) instead of trying to execute it like a function.
AttributeError: 'X' object has no attribute 'Y'
You are attempting to access an attribute or method on a `limits` object (e.g., a `Storage` or `Limiter` instance) that does not exist or is misspelled. This can also happen with incorrect usage of decorators.
fixReview the `limits` library's API documentation for the specific object you are using to ensure you are calling the correct attributes or methods and that your object is correctly initialized.
Audit
Dependencies
pythonrequiredRequires Python 3.10 or newer.
redisoptionalOptional, for Redis storage backend.
memcacheoptionalOptional, for Memcached storage backend.
pymongooptionalOptional, for MongoDB storage backend.
coredisoptionalOptional, for async Redis storage backend.
valkeyoptionalOptional, for Valkey storage backend.