---
title: "Rate limiting"
manual: "TYPO3 Explained"
version: "main"
permalink: "https://docs.typo3.org/permalink/t3coreapi:rate-limiting@main"
source: "ApiOverview/RateLimiting/Index.rst"
rendered: "2026-10-01T15:20:18+00:00"
---

# Rate limiting {#rate-limiting}

<!-- TODO: no Markdown rendering for "versionadded" -->

Previously, the backend and frontend password recovery features, as well as
the Extbase rate limiting, each created Symfony rate limiter factories
directly, bypassing TYPO3's factory. All consumers now use the central TYPO3
factory, which enables a unified admin override mechanism.

The `\TYPO3\CMS\Core\RateLimiter\RateLimiterFactory` is available
to serve as the single entry point for all rate limiting across the system.
A new `\TYPO3\CMS\Core\RateLimiter\RateLimiterFactoryInterface` extends
Symfony's `\Symfony\Component\RateLimiter\RateLimiterFactoryInterface` with
additional convenience methods for request-based and login rate limiting.

Extension developers should type-hint against
`\TYPO3\CMS\Core\RateLimiter\RateLimiterFactoryInterface` when
injecting the factory.

**Table of Contents**

-   [Overriding the rateLimiter via the TYPO3_CONF_VARS](https://docs.typo3.org/permalink/t3coreapi:overriding-the-ratelimiter-via-the-typo3-conf-vars@main)
-   [Example limiter ID for Extbase action](https://docs.typo3.org/permalink/t3coreapi:example-limiter-id-for-extbase-action@main)
-   [General-purpose rate limiting](https://docs.typo3.org/permalink/t3coreapi:general-purpose-rate-limiting@main)

## Overriding the `rateLimiter` via the TYPO3_CONF_VARS {#rate-limiting-typo3-conf-vars}

> [!NOTE]
> **See also**
>
> [$GLOBALS\['TYPO3_CONF_VARS'\]\['SYS'\]\['rateLimiter'\]](https://docs.typo3.org/permalink/t3coreapi:confval-globals-typo3-conf-vars-sys-ratelimiter@main)

## Example limiter ID for Extbase action {#rate-limiting-extbase-action}

The limiter ID for an Extbase action which uses the
`#[\TYPO3\CMS\Extbase\Attribute\RateLimit]` attribute is constructed using
the "slugified" class name and the action method name.

**EXT:my_extension/Classes/Controller/MyController.php**

```php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Controller;

use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Extbase\Attribute\RateLimit;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;

final class MyController extends ActionController
{
  #[RateLimit(
    limit: 5,
    interval: '10 minutes',
    message: 'ratelimit.dosomething',
  )]
  public function doSomethingAction(): ResponseInterface
  {
    return $this->redirect('index');
  }
}

```

The limiter ID for the action is:
`extbase-myvendor-myextension-controller-mycontroller-dosomethingaction`

## General-purpose rate limiting {#rate-limiting-general-purpose}

Extension developers can use the
`\TYPO3\CMS\Core\RateLimiter\RateLimiterFactory` for custom rate
limiting needs.

The `createRequestBasedLimiter()` method is the recommended entry point for
request-scoped rate limiting. It automatically extracts the client's remote IP
address from the [PSR-7 request](https://docs.typo3.org/permalink/t3coreapi:typo3-request@main) and uses it as the limiter
key:

**EXT:my_extension/Classes/RateLimiting/MyService.php**

```php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\RateLimiting;

use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\RateLimiter\RateLimiterFactoryInterface;

final readonly class MyService
{
  public function __construct(
    private RateLimiterFactoryInterface $rateLimiterFactory,
  ) {}

  public function doSomething(ServerRequestInterface $request): void
  {
    $limiter = $this->rateLimiterFactory->createRequestBasedLimiter(
      $request,
      [
        'id' => 'my-extension-action',
        'policy' => 'sliding_window',
        'limit' => 10,
        'interval' => '1 hour',
      ],
    );

    $limit = $limiter->consume();
    if (!$limit->isAccepted()) {
      // handle rate limit exceeded
    }
  }
}

```

For cases where a custom key is needed (for example, a user ID instead of the
IP address), the `createLimiter()` method accepts an explicit configuration
array and key:

**EXT:my_extension/Classes/RateLimiting/MyService.php (excerpt)**

```php
$limiter = $this->rateLimiterFactory->createLimiter(
    [
        'id' => 'my-extension-action',
        'policy' => 'sliding_window',
        'limit' => 10,
        'interval' => '1 hour',
    ],
    $userId
);
```

Pre-configured named services can also be defined in `Services.yaml`,
which are then injectable with the `create()` method from the
`\TYPO3\CMS\Core\RateLimiter\RateLimiterFactoryInterface`:

**EXT:my_extension/Configuration/Services.yaml**

```yaml
services:
  # ... other configuration

  myRateLimiter:
    class: TYPO3\CMS\Core\RateLimiter\RateLimiterFactory
    arguments:
      $config:
        id: 'my-custom-limiter'
        policy: 'sliding_window'
        limit: 5
        interval: '10 minutes'

```

Read [how to configure dependency injection in extensions](https://docs.typo3.org/permalink/t3coreapi:dependency-injection-in-extensions@main).
