Home / Symfony / New in Symfony 8.1: RateLimiter Improvements

New in Symfony 8.1: RateLimiter Improvements

Rate Limiting Controllers with the #[RateLimit] Attribute


Ayyoub AFW-ALLAH
Contributed by
Ayyoub AFW-ALLAH
in
#63907

The RateLimiter component lets you control how often an action can happen, but
until now you had to inject a limiter factory into your controller and write the
boilerplate code needed to build the key, consume a token and return a 429 response.

Symfony 8.1 adds a #[RateLimit] attribute that does all of this declaratively.
It references a limiter configured under framework.rate_limiter and, when the
limit is exceeded, the kernel automatically returns a 429 Too Many Requests
response with a Retry-After header:

use SymfonyComponentExpressionLanguageExpression;
use SymfonyComponentHttpKernelAttributeRateLimit;

class ApiController extends AbstractController
{
    // by default, the bucket is keyed by client IP + HTTP method + path
    #[RateLimit('api')]
    public function index(): JsonResponse { /* ... */ }

    // restrict the limit to specific HTTP methods
    #[RateLimit('api', methods: ['POST', 'PUT'])]
    public function edit(): JsonResponse { /* ... */ }

    // build the bucket key from a submitted field (a closure also works)
    #[RateLimit('per_account', key: new Expression('request.request.get("email")'))]
    public function resetPassword(): Response { /* ... */ }

    // consume several tokens per request for expensive endpoints
    #[RateLimit('api', tokens: 5)]
    public function export(): JsonResponse { /* ... */ }
}

The attribute is repeatable, so you can stack multiple limits on the same action
(all of them must pass), and you can also apply it to the controller class to rate
limit every action in it.

Calendar-Aligned Fixed Windows


Thibault Gattolliat
Contributed by
Thibault Gattolliat
in
#62127

The fixed_window policy counts hits in fixed time windows, but those windows
start on the first request. If you allow 10,000 calls per month and the first one
arrives on the 18th, the counter resets on the 18th of the following month instead
of at the beginning of the next calendar month.

Symfony 8.1 adds an anchor_at option that aligns fixed_window limiters to
a calendar. Windows then reset at anchor_at + n × interval, which is exactly
what you need for billing cycles, fiscal years, or fixed-day weekly resets:

# config/packages/rate_limiter.yaml
framework:
    rate_limiter:
        api_quota:
            policy: 'fixed_window'
            limit: 10000
            interval: '1 month'
            # the counter now resets on the 5th of every month at 00:00 UTC
            anchor_at: '2026-01-05 00:00:00 UTC'

The anchor_at value can be any string accepted by DateTimeImmutable.
Symfony computes each window by repeatedly adding the interval to it. This option
only works with the fixed_window policy and an interval of at least one month.


Sponsor the Symfony project.
Tagged:

Leave a Reply

Your email address will not be published. Required fields are marked *