How to Implement the Rate Limiter Component in a Symfony 5 Project

Learn how to implement Symfony’s Rate Limiter component to secure your API by controlling request frequency, preventing abuse, and ensuring application stability with practical code examples and configuration tips.

How to Implement the Rate Limiter Component in a Symfony 5 Project
Photo by Nathan Dumlao / Unsplash

APIs exposed to the public are often vulnerable to abuse through excessive or malicious requests. Fortunately, Symfony introduced a native Rate Limiter component starting in version 5.2. This powerful feature allows you to control how many requests users can make within a given time frame, helping prevent server overload and denial-of-service attacks.

In this guide, you'll learn how to set up Symfony's Rate Limiter, configure it for your application, and integrate it into your API using an event subscriber for clean and scalable implementation.

Requirements to Use Symfony's Rate Limiter

Before using the Rate Limiter component, your project must meet the following requirements:

  • Symfony version 5.2 or higher
  • PHP version 7.2.5 or higher

Ensure your project meets these versions before proceeding.

Installing the Rate Limiter Component

Start by installing the necessary Symfony package:

composer require symfony/rate-limiter

This command installs the rate-limiter package along with its dependencies such as symfony/lock and symfony/options-resolver.

Configuring the Rate Limiter in Symfony

Create the Configuration File

Create a file named rate_limiter.yaml in the config/packages directory:

# config/packages/rate_limiter.yaml

framework:
    rate_limiter:
        anonymous_api:
            policy: 'sliding_window'
            limit: 5
            interval: '1 minute'

Understanding the Configuration Options

You can also use the rate object instead of interval:

rate: { interval: '5 minutes', amount: 100 }

This means a user can make up to 100 requests every 5 minutes, but unused requests do not carry over to the next period.

Dealing with Semaphore Errors in PHP

If you are using a PHP version that has been compiled with the --enable-sysvsem flag, you can directly go to the next section. But if it's not the case, you will have to make some more modifications.

If you encounter the following error:

Semaphore extension (sysvsem) is required.

It means your PHP version doesn't support sysvsem. Instead of recompiling PHP, update your .env file:

LOCK_DSN=flock

Changing LOCK_DSN to flock bypasses the semaphore dependency and resolves the issue quickly.

Creating a Test API in Symfony

To test the rate limiter, let's scaffold a basic API:

Generate a Controller

Run the Symfony CLI to generate a controller:

php bin/console make:controller MainController

Define API and Web Routes

Edit the generated controller:

<?php

namespace App\Controller;

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

class MainController extends AbstractController
{
    /**
     * @Route("/api", name="api_index")
     */
    public function index(): Response
    {
        return $this->json([
            'message' => 'Hello World!',
        ]);
    }

    /**
     * @Route("/", name="app_home")
     */
    public function home(): Response
    {
        return new Response("Hello world !");
    }
}

The /api route will simulate a basic API endpoint, while / serves as a regular web page.

To test locally, run the Symfony server:

php -S localhost:8080 -t public

Visit http://localhost:8080/api to verify the JSON response.

{
    "message": "Hello World!"
}

Centralizing Rate Limit Logic with an Event Subscriber

Instead of adding rate-limiting code to every controller method, create an EventSubscriber to apply the logic globally to API routes.

Create the Subscriber

Create a new file at src/EventSubscriber/RateLimiterSubscriber.php:

<?php

namespace App\EventSubscriber;

use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\RateLimiter\RateLimiterFactory;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException;

class RateLimiterSubscriber implements EventSubscriberInterface
{
    private RateLimiterFactory $anonymousApiLimiter;

    public function __construct(RateLimiterFactory $anonymousApiLimiter)
    {
        $this->anonymousApiLimiter = $anonymousApiLimiter;
    }

    public static function getSubscribedEvents(): array
    {
        return [
            RequestEvent::class => 'onKernelRequest',
        ];
    }

    public function onKernelRequest(RequestEvent $event): void
    {
        $request = $event->getRequest();

        if (strpos($request->get("_route"), 'api_') !== false) {
            $limiter = $this->anonymousApiLimiter->create($request->getClientIp());

            if (!$limiter->consume(1)->isAccepted()) {
                throw new TooManyRequestsHttpException();
            }
        }
    }
}

How It Works

  • Listens to all HTTP requests
  • Checks if the route name begins with api_
  • Applies the rate limiter using the client’s IP as an identifier
  • Throws a 429 Too Many Requests error if the limit is exceeded

Test the Rate Limiter

Open your browser and visit http://localhost:8080/api. Refresh more than 5 times within a minute and you’ll receive a 429 Too Many Requests error — confirming the limiter works.

Conclusion

Implementing a rate limiter in your Symfony project is a crucial step toward securing your API and improving performance under load. By using Symfony’s native Rate Limiter component, you can control traffic, prevent abuse, and handle excessive requests gracefully.

Want to see the complete working example? Check out the source code here:
GitHub – MrAnyx/test-rate-limiter