Install & Compatibility
Where this runs
tested against v4.1.1 · 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.930 runs
installs and imports cleanly · install 0.0s · import 0.819s · 37.9MB
glibcpy 3.10–3.930 runs
installs and imports cleanly · install 3.8s · import 0.731s · 38MB
39MB installed
● package 39MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
Limiter
✓ from flask_limiter import Limiter
get_remote_address
✓ from flask_limiter.util import get_remote_address
Limit
✓ from flask_limiter import Limit
✗ from flask_limiter.limits import Limit
As of v4.0.0, internal submodules are prefixed with an underscore, and direct imports from them (e.g., `flask_limiter.limits`) are deprecated. Import from the root `flask_limiter` namespace instead.
Initializes a Flask application with global and per-route rate limits. It uses `get_remote_address` as the default key function and specifies a default storage URI. Routes demonstrate application-wide limits, specific route limits, combined limits, and exemptions. An error handler for HTTP 429 is included for custom responses.
import os
from flask import Flask
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
app = Flask(__name__)
# Configure storage_uri, using in-memory for example, or from an environment variable
# In-memory storage is for development/testing only and should not be used in production with multiple workers.
# For production, use backends like Redis: 'redis://localhost:6379'
storage_uri = os.environ.get('FLASK_RATELIMIT_STORAGE_URI', 'memory://')
limiter = Limiter(
key_func=get_remote_address,
app=app,
default_limits=["200 per day", "50 per hour"],
storage_uri=storage_uri,
strategy="fixed-window" # Or 'moving-window', 'sliding-window-counter'
)
@app.route("/slow")
@limiter.limit("1 per day")
def slow():
return ":("
@app.route("/medium")
@limiter.limit("1/second", override_defaults=False)
def medium():
return ":|"
@app.route("/fast")
def fast():
return ":)"
@app.route("/ping")
@limiter.exempt
def ping():
return "PONG"
# Example error handler for rate limit exceeded (HTTP 429)
@app.errorhandler(429)
def ratelimit_handler(e):
return f"Rate limit exceeded: {e.description}", 429
if __name__ == '__main__':
app.run(debug=True)
Debug
Known issues
breakingVersion 4.0.0 introduced significant breaking changes in module structure and limit definition. All internal submodules are now prefixed with an underscore, and direct imports from them (e.g., `from flask_limiter.limits import Limit`) are deprecated. Instead, import classes like `Limit`, `RouteLimit`, `ApplicationLimit`, and `MetaLimit` directly from the root `flask_limiter` namespace.fixUpdate imports to use `from flask_limiter import ClassName` (e.g., `from flask_limiter import Limit`) and adjust how limits are configured, leveraging the new limit description classes.
affects: >=4.0.0
breakingVersion 3.0.0 changed the `Limiter` constructor arguments. `key_func` is now a mandatory positional argument, and all other arguments must be passed as keyword arguments. The `RATELIMIT_STORAGE_URL` configuration variable was removed, and legacy Flask < 2 compatibility was dropped.fixEnsure `key_func` is the first argument in `Limiter()` and all subsequent arguments are explicitly named (e.g., `Limiter(get_remote_address, app=app, storage_uri='...')`). Replace `RATELIMIT_STORAGE_URL` with `storage_uri` or `RATELIMIT_STORAGE_URI` in Flask config.
affects: >=3.0.0
gotchaUsing in-memory storage (`memory://`) in production with multiple worker processes will lead to inaccurate and unreliable rate limiting. Each worker will maintain its own independent limit state, making global rate limits ineffective.fixAlways configure a persistent storage backend (e.g., Redis, Memcached, MongoDB, Valkey) for production deployments by setting `storage_uri` or the `RATELIMIT_STORAGE_URI` Flask config variable.
affects: All
deprecatedThe 3.13 release was yanked from PyPI due to compatibility issues with Flask-AppBuilder and Airflow. Users who installed this specific version might encounter unexpected behavior or errors.fixAvoid using version 3.13. If you are on 3.13, downgrade to a stable 3.x release (e.g., 3.12 or earlier) or upgrade to version 4.0.0 or later.
affects: 3.13
breakingFlask-Limiter frequently adjusts its supported Python versions. For example, Python 3.9 support was dropped in v3.12, and Python 3.8 support was dropped in v3.9.0. Currently, Python >=3.10 is required.fixAlways check the `requires_python` metadata (or `py_modules` in the PyPI classifiers) for the specific Flask-Limiter version you intend to use and ensure your Python environment meets the requirements.
affects: Various, depending on minor/major versions
gotchaWhen deploying behind a proxy (e.g., Nginx, Gunicorn), `get_remote_address` might return the proxy's IP address instead of the client's. This can lead to all requests being limited by the proxy's IP, effectively acting as a single global limit for all users.fixProperly configure your proxy to forward the client's IP in a header (e.g., `X-Forwarded-For`) and configure Flask-Limiter to use this header, potentially with a custom `key_func` or by configuring `RATELIMIT_HEADERS_ENABLED` and `RATELIMIT_HEADER_ID`.
affects: All
Errors
Common errors & fixes
TypeError: Limiter.__init__() got multiple values for argument 'key_func'
This error occurs when the 'app' instance is passed as a positional argument after 'key_func' during Limiter initialization, causing Python to interpret 'app' as a second value for 'key_func' because 'key_func' is the only positional argument.
fixPass the 'app' instance using the keyword argument `app=app` during Limiter initialization. For example: `limiter = Limiter(key_func=get_remote_address, app=app, default_limits=['200 per day'])`.
ModuleNotFoundError: No module named 'flask_limiter.wrappers'
The 'flask_limiter.wrappers' module was removed as a breaking change in Flask-Limiter version 3.13, causing applications that directly import or rely on this module (especially older versions of dependent libraries like Flask-AppBuilder or Apache Superset) to fail.
fixPin your 'flask-limiter' dependency to a version prior to 3.13 (e.g., `flask-limiter==3.12.1`) or update any dependent libraries to versions compatible with newer 'flask-limiter' releases.
flask-limiter redis not working
This issue, or similar 'time out' errors, typically arises when the specified storage backend (like Redis, Memcached, or MongoDB) is not running, is misconfigured (e.g., incorrect `storage_uri`), or the necessary Python client library for that backend has not been installed as an extra dependency.
fixEnsure the chosen storage backend service is running and accessible, verify the `storage_uri` is correctly formatted (e.g., `redis://localhost:6379`), and install the required extra dependencies for your backend (e.g., `pip install Flask-Limiter[redis]`).
AttributeError: module 'configparser' has no attribute 'SafeConfigParser'
This error occurs because 'SafeConfigParser' was deprecated and removed in Python 3.10 and later, and an older version of 'flask-limiter' or its underlying 'limits' library attempts to use it.
fixUpgrade 'flask-limiter' and its 'limits' dependency to versions compatible with Python 3.10+ (typically `flask-limiter>=2.0.0` and `limits>=2.0.0`).
Upgrade
Version history
4.1.1latest on PyPI · released Dec 6, 2025
Audit
Dependencies
redisoptionalOptional backend for rate limit storage
pymemcacheoptionalOptional backend for rate limit storage
pymongooptionalOptional backend for rate limit storage
valkey-pyoptionalOptional backend for rate limit storage
clickoptionalRequired for Flask CLI commands if 'cli' extra is used