This website uses cookies

Our website, platform and/or any sub domains use cookies to understand how you use our services, and to improve both your experience and our marketing relevance.

📣 The Agency Advantage Summit is Here. Join 2,000+ digital pros for 2 days of AI-powered strategies. Register for Free →

How to Set API Rate Limiting in Laravel: All You Need To Know

Updated on May 2, 2025

11 Min Read
laravel throttle

Key Takeaways:

  • Laravel’s rate limiting feature allows you to control the number of requests a user can make to your application within a given timeframe, protecting against abuse and ensuring availability for legitimate users.
  • You can implement rate limiting using the throttle middleware, specifying the maximum number of requests and the time window (e.g., throttle:3,10 for 3 requests every 10 minutes).
  • Dynamic rate limiting allows you to set limits based on user attributes (like subscription level), providing granular control over access to your application’s resources.

Once traffic to your Laravel API starts to climb, putting limits on how often users can hit your endpoints becomes necessary. Without controls in place, a surge in requests can overload your app, open the door to abuse, and slow everything down for everyone.

This is where implementing rate limiting makes sense. In Laravel, you can approach this in several ways—setting general limits for all traffic, applying rules to specific routes, or capping requests based on individual users.

In this blog, we’ll take a closer look at how to set each of these up in a Laravel app.

Understanding Rate Limiting

Rate limiting helps control how often users can hit your API. Without it, one user—or a bot—could flood your server with nonstop requests, eating up resources and making the service unreliable for everyone else. Setting fair limits lets you keep things stable, prevent abuse, and make sure your API stays responsive under load.

What Is the Difference Between Throttle and Rate Limit?

Throttle and rate limiting are two closely related concepts used to control the flow of requests in Laravel applications, but they function in different ways. Throttle focuses on managing how requests are handled over time, while rate limiting defines specific boundaries for the number of allowed requests.

The table below provides a clear comparison to help you understand their unique purposes and applications.

Throttle Rate Limit
Definition A mechanism to control the flow of requests to an application. The specific number of allowed requests within a defined timeframe.
Purpose Ensures controlled traffic and prevents abuse by applying rate limits. Sets the maximum limit of requests a user or IP can make.
Scope Broad: enforces rate limits dynamically based on application logic. Narrow: defines fixed rules for request limits per user or IP address.
Configuration Configured through middleware (ThrottleRequests). Defined using specific rate-limiting rules in RateLimiter or middleware.
Example Throttle allows up to 10 requests per minute per user/IP. Rate limit sets the exact limit of 10 requests per minute.
Flexibility Provides customizable logic for different user types or endpoints. Primarily focuses on enforcing static or predefined limits.
Usage in Laravel Implemented via ThrottleRequests middleware or custom logic. Configured using the RateLimiter class or Laravel’s default middleware.

How To Implement Rate Limiting in Laravel?

This guide walks through implementing rate limiting in Laravel, starting with basic IP-based throttling and progressing to user-based rate limiting with Sanctum authentication. We’ll use the command prompt for all operations, with two windows:

Managed Laravel Hosting: Your Laravel Performance Boost!

Elevate Your Laravel Experience with Cloudways’ Laravel Managed Hosting – Where Expertise Meets Exceptional Performance.

  • Window 1: Running Laravel (php artisan serve)
  • Window 2: Executing API tests (curl commands)

Prerequisites

Before starting, ensure you have:

  • PHP 8.2+ and Composer installed.
  • Laravel 10 (install via composer global require laravel/installer).
  • A database (MySQL, SQLite, etc.).
  • (Optional) Postman or cURL to test API endpoints.

Part 1: Global Rate Limiting

Set up a new Laravel project by running the command below. Name your project anything you like.

laravel new laravel-rate-limiting-project

laravel new laravel-rate-limiting-project

Now head to: cd laravel-rate-limiting-project

cd laravel-rate-limiting-project

Now start the development server by running this command:

php artisan serve

php artisan serve

Next, create a test API route

Open routes/api.php and add:

Route::get('/hello', function () {

return response()->json(['message' => 'Hello, World!']);

});

Open routesapi.php and add

Open it with Notepad or any other text editor and add the test API route anywhere after the existing route definitions in your routes/api.php.

routesapi.php

Save the file.

Test it with cURL (in a new terminal):

curl http://127.0.0.1:8000/api/hello

Expected output: {“message”:”Hello, World!”}

{messageHello, World!}

I can also view the same message if I visit “http://127.0.0.1:8000/api/hello in my browser.

Hello World

If I keep refreshing this URL, you can see that there is no rate limiting applied to this route.

Now let’s see how to add rate limiting, starting with the global rate limit that applies to all API routes.

Before we start…let’s see all the endpoints for our laravel project by running:

php artisan route:list

php artisan routelist

In the screenshot above, I can see the new API route we created, “api/hello”.

In Laravel, rate limiting for API routes is defined in the Kernel.php file.

defined in the Kernel.php file.

To set a global rate limit for all API routes, edit app/Http/Kernel.php and update the api middleware group to:

'api' => [

\Illuminate\Routing\Middleware\ThrottleRequests::class.':3,1',

],

This will allow 3 requests per minute per IP address.

3 requests per minute per IP address.

Replace the code I provided above with the default code in the file, just like in the image. Don’t forget to save the file.

Now, if I refresh “http://127.0.0.1:8000/api/hello more than 3 times quickly, I’ll see a “Too Many Requests” error.

I’ll see a “Too Many Requests” error.

But remember, the rate limiting that we implemented is global, so applies to all routes. So if I create another route in the routes/api.php file and test the new route, it will also give me the “Too Many Requests” error.

Here is the new route I declared:

Route::get('/second', function () {

return response()->json(['message' => 'second route']);

});

Here is the new route I declared

And now if I visit “http://127.0.0.1:8000/api/second and refresh quickly 4 times, I see the error.

Too many requests

Unlock Laravel’s Potential with Cloudways’ Laravel Hosting

Laravel Hosting Taken to the Next Level – Cloudways’ Managed Hosting Offers Unbeatable Speed and Reliability.

Part 2: Route-Specific Rate Limiting

To apply a custom limit on a specific route, use the throttle middleware directly in routes/api.php:

For example:

Route::middleware('throttle:3,1')->get('/limited', function () {

return response()->json(['message' => 'You can only call this 3 times per minute!']);

});

This allows 3 requests per minute to /api/limited per IP.

Open routes/api.php and add the following at the bottom (or anywhere inside the file):

Route::middleware('throttle:3,1')->get('/limited', function () {

return response()->json(['message' => 'You can only call this 3 times per minute!']);

});

Like so:

You can only call this 3 times per minute

We can test this with: curl http://127.0.0.1:8000/api/limited

Running the same command 4 times will show this message: “Too Many Attempts.”

Too Many Attempts

As we can see, now rate limiting is applied to the “/limited” route.

Now let’s move on to see how to apply rate limiting to a specific user.

Part 3: User-Based Rate Limiting

So far, we’ve already set up a Laravel project, covered global and route-specific rate limits, and got the basics running. Now, we’ll level things up and control how many requests each authenticated user can make—this is especially useful when you want to offer tiered access (like free vs premium users).

Unlike IP-based limits that throttle traffic regardless of who’s sending it, user-based throttling tracks usage per authenticated account. This is perfect when you want, say, a free user to be allowed only 3 API calls per minute, while a premium user can make 60.

Set Up a Simple User Table

For this tutorial, I’m using SQLite because it’s fast, file-based, and doesn’t need server setup. You can use MySQL or Postgres as well—just update your .env accordingly.

First, configure the .env:

DB_CONNECTION=sqlite

Make sure to remove any other DB_* lines related to host, port, username, etc.

related to host, port, username

Then, create the database file:

type nul > database\database.sqlite

This will create an empty database.sqlite file in the database folder.

And run the migrations to create the default tables:

php artisan migrate

And run the migrations to create the default tables

Add a Couple of Users via Tinker

We’ll use Laravel Tinker to insert a couple of users—one regular, one premium.

php artisan tinker

Then run:

User::create([

    'name' => 'Test User',

    'email' => '[email protected]',

    'password' => bcrypt('password123')

]);

 

User::create([

    'name' => 'Premium User',

    'email' => '[email protected]',

    'password' => bcrypt('password123')
]);

Exit the Tinker using Ctrl + Ct.

Exit the Tinker using Ctrl + Ct.

Install Sanctum for API Authentication

We’ll need authentication to distinguish between users. Laravel Sanctum is perfect for lightweight API token handling.

composer require laravel/sanctum

composer require laravelsanctum

Then publish Sanctum’s config and migration files:

php artisan vendor:publish –provider=”Laravel\Sanctum\SanctumServiceProvider”

php artisan migrate

Next, plug Sanctum into your API middleware stack. Open app/Http/Kernel.php and find the api middleware group. Replace it like this:

'api' => [

\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,

'throttle:api',

\Illuminate\Routing\Middleware\SubstituteBindings::class,

],

Define User-Based Rate Limits

Open app/Providers/RouteServiceProvider.php and find the configureRateLimiting() method. If it’s not there, create it inside the class.

Add the following logic:

protected function configureRateLimiting()

{

    // Default API rate limit (can keep or adjust as needed)

    RateLimiter::for('api', function (Request $request) {

        return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());

    });

 

    // Standard user: 3 requests per minute

    RateLimiter::for('user', function (Request $request) {

        return Limit::perMinute(3)->by(optional($request->user())->id ?: $request->ip());

    });

 

    // Premium user: 6 requests per minute

    RateLimiter::for('premium', function (Request $request) {

        return $request->user() && $request->user()->email === '[email protected]'

            ? Limit::perMinute(6)->by($request->user()->id)

            : Limit::perMinute(3)->by(optional($request->user())->id ?: $request->ip());

    });

}

This logic sets 3 requests/minute for normal users and 6 requests/minute for the premium users.

You can replace the entire code in your file with this if you don’t know how to add this code to your file:

<?php

namespace App\Providers;

use Illuminate\Cache\RateLimiting\Limit;

use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;

use Illuminate\Http\Request;

use Illuminate\Support\Facades\RateLimiter;

use Illuminate\Support\Facades\Route;

class RouteServiceProvider extends ServiceProvider

{

/**

* The path to the "home" route for your application.

*

* Typically, users are redirected here after authentication.

*

* @var string

*/

public const HOME = '/home';

/**

* Define your route model bindings, pattern filters, and other route configuration.

*

* @return void

*/

public function boot()

{

$this->configureRateLimiting();

$this->routes(function () {

Route::middleware('api')

->prefix('api')

->group(base_path('routes/api.php'));

Route::middleware('web')

->group(base_path('routes/web.php'));

});

}

/**

* Configure the rate limiters for the application.

*

* @return void

*/

protected function configureRateLimiting()

{

// Global API rate limit (fallback)

RateLimiter::for('api', function (Request $request) {

return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());

});

// Standard user rate limit (3 requests/minute)

RateLimiter::for('user', function (Request $request) {

return Limit::perMinute(3)->by($request->user()?->id ?: $request->ip());

});

// Premium user rate limit (6 requests/minute)

 // Premium user rate limit (6 requests/minute)
    RateLimiter::for('premium', function (Request $request) {
        return $request->user() && $request->user()->email === '[email protected]'
            ? Limit::perMinute(6)->by($request->user()->id)
            : Limit::perMinute(3)->by($request->user()?->id ?: $request->ip());
    });
}
}

Now that you’ve configured the rate limiters, you can apply the new rate limiting logic to your API routes. You do this by using the throttle middleware in your routes/api.php file.

Modify routes/api.php

You will use the throttle:user middleware for normal users, and throttle:premium middleware for premium users.

Example of how to apply rate limiters to routes:

use Illuminate\Http\Request;

use Illuminate\Support\Facades\Auth;

use Illuminate\Support\Facades\Route;

// Public route (no rate limit)

Route::get('/public', function () {

return ['message' => 'Unlimited access'];

});

// Login route

Route::post('/login', function (Request $request) {

$credentials = $request->validate([

'email' => 'required|email',

'password' => 'required'

]);

if (!Auth::attempt($credentials)) {

return response()->json(['error' => 'Unauthorized'], 401);

}

return [

'token' => $request->user()->createToken('api')->plainTextToken

];

});

// Protected route with user-based rate limiting (3 requests/minute)

Route::middleware(['auth:sanctum', 'throttle:user'])->get('/protected', function () {

return [

'message' => 'Protected content (3 requests/min)',

'user' => auth()->user()->only(['id', 'name', 'email'])

];

});

// Premium route with premium user-based rate limiting (6 requests/minute for premium users)

Route::middleware(['auth:sanctum', 'throttle:premium'])->get('/premium', function () {

return [

'message' => 'Premium content (6 requests/min)',

'user' => auth()->user()->only(['id', 'name', 'email'])

];

});

Feel free to copy and paste the entire code below to your file:

<?php

use Illuminate\Http\Request;

use Illuminate\Support\Facades\Route;

/*

|--------------------------------------------------------------------------

| API Routes

|--------------------------------------------------------------------------

|

| Here is where you can register API routes for your application. These

| routes are loaded by the RouteServiceProvider within a group which

| is assigned the "api" middleware group. Enjoy building your API!

|

*/

// Public route (no rate limit)

Route::get('/hello', function () {

return response()->json(['message' => 'Hello, World!']);

});

// Another public route (no rate limit)

Route::get('/second', function () {

return response()->json(['message' => 'second route']);

});

// Route for user details (requires authentication)

Route::middleware('auth:sanctum')->get('/user', function (Request $request) {

return $request->user();

});

// Protected route with user-based rate limiting (3 requests/minute)

Route::middleware(['auth:sanctum', 'throttle:user'])->get('/protected', function () {

return response()->json(['message' => 'Protected content (3 requests/min)', 'user' => auth()->user()]);

});

// Route for premium users with higher rate limiting (6 requests/minute)

Route::middleware(['auth:sanctum', 'throttle:premium'])->get('/premium', function () {

return response()->json(['message' => 'Premium content (6 requests/min)', 'user' => auth()->user()]);

});

// Test route with custom rate limit (3 requests/minute for normal users)

Route::middleware('throttle:3,1')->get('/limited', function () {

return response()->json(['message' => 'You can only call this 3 times per minute!']);

});

Here’s what’s happening in the file:

  • Public routes /hello and /second that we created earlier are open to everyone—no login or limits.
  • /protected uses throttle:user → 3 requests/minute for normal users.
  • /premium uses throttle:premium → 6 requests/minute for premium users.

Test the Rate Limiting

After adding the routes, you can test them to make sure the rate limiting works correctly. First, get tokens for both users:

For regular user ([email protected]):

After adding the routes, you can test them to make sure the rate limiting works correctly. First, get tokens for both users:

For regular user ([email protected]):

curl -X POST http://127.0.0.1:8000/api/login ^
  -H "Content-Type: application/json" ^
  -d "{\"email\":\"[email protected]\",\"password\":\"password123\"}"

For premium user ([email protected]):

curl -X POST http://127.0.0.1:8000/api/login ^
  -H "Content-Type: application/json" ^
  -d "{\"email\":\"[email protected]\",\"password\":\"password123\"}"

Running both of them gives me two tokens:

them gives me two tokens

Now let’s test the rate limiting for both users, “standard” and “premium”. Remember, 3 requests/min for standard and 6 requests/min for premium.

To see our user based rate limiter in action, we can modify our Handler.php file like this to get an error message in JSON instead of HTML.

Here’s how to do it:

Edit app/Exceptions/Handler.php:

<?php

namespace App\Exceptions;

use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;

use Illuminate\Http\Exceptions\ThrottleRequestsException;

use Throwable;

class Handler extends ExceptionHandler

{

// ... other code ...

public function render($request, Throwable $exception)

{

// Convert throttle exceptions to JSON responses

if ($exception instanceof ThrottleRequestsException) {

return response()->json([

'error' => 'rate_limit_exceeded',

'message' => 'Too many requests. Please try again later.',

'retry_after' => $exception->getHeaders()['Retry-After'] ?? 60,

'limit' => $this->getRateLimitFromException($exception),

], 429);

}

return parent::render($request, $exception);

}

protected function getRateLimitFromException(ThrottleRequestsException $exception)

{

// Extract rate limit info from exception message

if (preg_match('/\d+/', $exception->getMessage(), $matches)) {

return (int)$matches[0];

}

return null;

}

}

Save the file.

Now test the rate limit for standard user by running the command below 4 times. At the 4th attempt, you’ll get an error saying: Too many requests. Please try again later.

curl http://127.0.0.1:8000/api/standard ^

-H “Authorization: Bearer 16|tCDoWhoAVI4YfjRJIZHNyOr0svCADEEFYfzIILYq70a259b6”

Authorization Bearer

For premium user, you’ll see the same error at your 7th request.

curl http://127.0.0.1:8000/api/premium ^

-H “Authorization: Bearer 17|9pBNtUebEeZPKCKti6xaRdFZPdLFXazI18Jl5RKrd91e43f0”

Too many requests, please try again later

And that is it. This is how user based API rate limiting works.

Stop Wasting Time on Servers

Cloudways handle server management for you so you can focus on creating great apps and keeping your clients happy.

Wrapping Up!

Adding rate limiting to your Laravel API is a smart way to keep things running smoothly without letting heavy traffic crash your app. It’s like putting up a “one-at-a-time” rule so everyone gets a fair turn.

Here’s what we went over:

Basic rate limits – Setting a simple cap for all API requests

Custom limits per route – Letting certain endpoints have their own rules

User-specific controls – Giving different access levels to regular vs. premium users

These steps help balance load, stop abuse, and make sure your API stays fast for everyone.

Stuck somewhere? Drop a comment—I’m happy to help!

Share your opinion in the comment section. COMMENT NOW

Share This Article

Abdul Rehman

Abdul is a tech-savvy, coffee-fueled, and creatively driven marketer who loves keeping up with the latest software updates and tech gadgets. He's also a skilled technical writer who can explain complex concepts simply for a broad audience. Abdul enjoys sharing his knowledge of the Cloud industry through user manuals, documentation, and blog posts.

×

Webinar: How to Get 100% Scores on Core Web Vitals

Join Joe Williams & Aleksandar Savkovic on 29th of March, 2021.

Do you like what you read?

Get the Latest Updates

Share Your Feedback

Please insert Content

Thank you for your feedback!

Do you like what you read?

Get the Latest Updates

Share Your Feedback

Please insert Content

Thank you for your feedback!

Want to Experience the Cloudways Platform in Its Full Glory?

Take a FREE guided tour of Cloudways and see for yourself how easily you can manage your server & apps on the leading cloud-hosting platform.

Start my tour