---
title: "Rails 8 introduces a built-in rate limiting API"
description:
  "Rails 8.0 adds rate limiting to ActionController which uses Active Support
  cache by default"
canonical_url: "https://www.bigbinary.com/blog/rails-8-rate-limiting-api"
markdown_url: "https://www.bigbinary.com/blog/rails-8-rate-limiting-api.md"
---

# Rails 8 introduces a built-in rate limiting API

Rails 8.0 adds rate limiting to ActionController which uses Active Support cache
by default

- Author: Yedhin Kizhakkethara
- Published: February 13, 2024
- Categories: Rails, Rails 8

In the dynamic world of web development, managing the flow of requests is
crucial for maintaining a responsive and reliable application. Rate limiting is
a powerful technique that acts as the traffic cop for your API, ensuring fair
access to resources and preventing potential chaos. In a nutshell, rate limiting
is the practice of controlling the rate of requests a user, device, or
application can make within a set timeframe.

In this blog post, we'll delve into the concept of rate limiting, exploring its
significance and implementation in Rails 8.0.

## The Need for Rate Limiting

It's crucial in ensuring the following:

- Security Shield: Guards against Denial-of-Service (DoS) attacks, thwarting
  malicious attempts to flood your app and crash it.
- Resource Balance: Prevents resource abuse by capping heavy users, ensuring
  fair resource distribution and maintaining optimal app performance.
- Brute-Force Defender: Stalls hackers attempting password guesses or exploiting
  vulnerabilities through relentless, repeated attempts.

## How Rack::Attack Paved the Way

In the pre-Rails 8.0 era, the go-to solution for rate limiting was the
[`rack-attack`](https://github.com/rack/rack-attack) gem. This gem allowed
developers to set up rate-limiting rules by adding custom code in the
`rack_attack.rb` file. While effective, this approach required manual
intervention for each endpoint and could become cumbersome in a growing
application. This external dependency brought its own set of challenges, such as
the need for custom code and constant vigilance over rate-limited endpoints.

## Rails 8.0: Native Rate Limiting

Rails 8.0 brings a native rate-limiting feature to the Action Controller,
streamlining the process and eliminating the need for external gems. Developers
can now set rate limits directly within their controllers using the `rate_limit`
method.

Let's take a look at the usage:

### Define Limits

Utilize the `rate_limit` method within your controller actions, specifying the
maximum allowed requests and the corresponding timeframe. The `rate_limit`
method accepts the following parameters:

- `to`: The maximum number of requests allowed, beyond which the rate limiting
  error will be raised, that is with a **429 Too Many Requests** response.
- `within`: The maximum number of requests allowed in a given time window.
- `only`: Which all controller actions ought to be rate limited.
- `except`: Which all controller actions to be omitted from rate limiting.

An example:

```rb
class SignupController < ApplicationController
  rate_limit to: 4, within: 1.minute, only: :create

  def create
    # ...
  end
end
```

### Granular Control

Target specific actions or employ custom logic for nuanced control. For
instance, you can limit requests based on domain instead of IP address.

```rb
rate_limit to: 4, within: 1.minute, by: -> { request.domain }, only: :create
```

### Tailored Responses

By default, rate-limited requests receive a `429 Too Many Requests` error.
However, you can personalize the response for a more informative user
experience.

```rb
rate_limit to: 4, within: 1.minute, with: -> { redirect_to(ip_restrictions_controller_url), alert: "Signup Attempts failed four times. Please try again later." }, only: :create
```

## Custom Cache Stores

The Rails 8.0 rate-limiting implementation at the moment allows us to make use a
wide range of backends as its store.

It includes:

- Memcached
- Redis (including alternative Redis clients like Dalli)
- Database-backed stores
- File-based stores

The Rate Limiting API seamlessly integrates with Rails' caching mechanisms,
leveraging
[`ActiveSupport::Cache`](https://api.rubyonrails.org/classes/ActiveSupport/Cache.html)
stores. Developers can specify custom cache stores if they require separate
handling for rate limits compared to other cache data. This integration ensures
efficient storage and retrieval of rate limit data, optimizing performance. An
example:

```rb
class SignupController < ApplicationController
  RATE_LIMIT_STORE = ActiveSupport::Cache::RedisCacheStore.new(url: ENV["REDIS_URL"])
  rate_limit to: 8, within: 2.minutes, store: RATE_LIMIT_STORE
end
```

## What to look forward to

At the moment the built-in rate limiting feature is limited in its
extensibility. There are cases where this feature cannot be used as a direct
replacement for logic that's based on `rack-attack` gem. A good example is a
scenario where we might want to use an exponential backoff based rate limiting
algorithm, which can be implemented using `rack-attack` gem but not with the
built-in Rails feature at the moment.

Right now, we are constrained to stick to the default cache counter algorithm
that Rails comes shipped with. In the future, we can expect a more generic
limiter interface, allowing users to explore advanced rate-limiting algorithms
such as exponential backoff, leaky bucket, or token bucket, etc. This change
would open the door for developers to swap the implementation based on their
specific requirements.

Please check out the following pull requests for more details:

- https://github.com/rails/rails/pull/50490
- https://github.com/rails/rails/pull/50781

## Links

- [Human page](https://www.bigbinary.com/blog/rails-8-rate-limiting-api)
