Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Throttle Laravel Package

alt-three/throttle

Alt Three Throttle provides configurable request rate limiting for Laravel applications. It offers middleware and helpers to protect routes from abuse, control traffic spikes, and return appropriate throttling responses using your chosen cache store.

View on GitHub
Deep Wiki
Context7

Getting Started

This package is a Laravel 5-era middleware that rate-limits requests, most likely by IP (and possibly route) using the cache. It is archived (last release September 2018), so treat it as legacy-maintenance only. For a new project, use Laravel's built-in throttle middleware instead; for an inherited Laravel 5.x app, here is the shortest path to using it.

  1. Install with Composer, checking the version constraints first:
composer require alt-three/throttle
  1. Register the service provider. On Laravel 5.5+ package discovery should handle AltThree\Throttle\ThrottleServiceProvider; on older versions add it to config/app.php.

  2. Register the route middleware alias in app/Http/Kernel.php:

protected $routeMiddleware = [
    // ...
    'throttle' => \AltThree\Throttle\Middleware\ThrottleMiddleware::class,
];
  1. Publish and inspect the config:
php artisan vendor:publish --provider="AltThree\Throttle\ThrottleServiceProvider"

Open config/throttle.php and confirm the limit/window/cache key names for your installed version before relying on them.

  1. First use case — protect an API group:
Route::group(['prefix' => 'api', 'middleware' => 'throttle'], function () {
    Route::get('/posts', 'PostController@index');
});

Verify it works by hitting the route in a loop and confirming you receive 429 Too Many Requests and any rate-limit headers. Then inspect the cache store to see the keys the middleware creates; that tells you what the limiter is actually keyed on.

Implementation Patterns

Use config for the global default, middleware parameters for exceptions. Most Laravel throttle middleware accepts throttle:60,1-style parameters (attempts, decay minutes). If this version's signature supports them, use that for per-route overrides; otherwise define separate route groups or set the limit in config/throttle.php.

Route::group(['prefix' => 'api', 'middleware' => 'throttle:60,1'], function () {
    // normal API routes
});

Route::group(['prefix' => 'api/auth', 'middleware' => 'throttle:5,1'], function () {
    Route::post('/login', 'AuthController@login');
});

Choose the cache store deliberately. The limiter is only as good as its cache. Use Redis or Memcached in production, especially across multiple app servers. The array driver resets per request and effectively disables throttling; the file driver works on a single node but adds lock contention and is not shared across servers.

Separate API and web responses. A browser hitting a throttled page should get an HTML error or redirect; an API client should get JSON with a Retry-After header. If the package returns a generic response, wrap or replace the middleware so $request->expectsJson() controls the response shape.

Place it correctly in the middleware stack. If the limiter keys by IP, put it early to reject abusive traffic before session/auth work. If you extend it to key by authenticated user, it must run after auth. Middleware order is part of your rate-limit semantics, not an afterthought.

Extend by copying, not monkey-patching. The package exposes limited extension points. For custom keying (user ID + route + method), write an app-level middleware using the same cache primitives:

public function handle($request, Closure $next)
{
    $key = 'throttle:'.($request->user()->id ?? $request->ip()).':'.$request->path();

    if (Cache::add($key, 1, 1)) {
        return $next($request);
    }

    $hits = Cache::increment($key);

    if ($hits > 60) {
        return response()->json(['message' => 'Too many requests'], 429, [
            'Retry-After' => Cache::getSecondsLeft($key) ?? 60,
        ]);
    }

    $response = $next($request);
    $response->headers->set('X-RateLimit-Remaining', max(0, 60 - $hits));

    return $response;
}

Test it explicitly. Flush the relevant cache in setUp() so counters do not leak between tests. Assert the 429 status and headers on the Nth request. Use $this->withoutMiddleware(ThrottleMiddleware::class) for unrelated feature tests so a busy test suite does not trip limits by accident.

Plan the migration. Laravel 5.2+ ships Illuminate\Routing\Middleware\ThrottleRequests, and Laravel 8+ adds named rate limiters via RateLimiter::for(). Replacing this package's alias with the framework middleware is usually a one-line kernel change, followed by removing the dependency. That is the healthiest day-to-day trajectory for an app using this package.

Gotchas and Tips

  • Archived means frozen. No PHP 8 or Laravel 6+ compatibility fixes, no security patches, and no guarantee the middleware signature matches newer framework conventions. Pin your Laravel/PHP versions and budget for removal.
  • It is largely redundant. Laravel introduced built-in request throttling in 5.2. Before adopting or keeping this package, confirm whether you actually need its specific headers, keying, or exception behavior. If not, delete it and use the framework middleware.
  • Proxy IPs collapse your buckets. Behind a load balancer, $request->ip() may be the proxy's IP unless TrustedProxies is configured. Every client then shares one rate-limit bucket, and legitimate traffic gets throttled while attackers do not.
  • Check what the key includes. If the key is only the IP, /api/posts and /api/comments share one limit. If it includes the path, a client can double its effective limit by alternating routes. Know which behavior you have and document it.
  • config:cache hides .env changes. After changing throttle settings in .env, run php artisan config:clear (or re-cache) before assuming the limit changed.
  • The array cache store silently disables enforcement. This is the most common false "it works locally" failure; verify with the same cache driver used in production.
  • Race conditions depend on the store. Cache::increment is atomic on Redis/Memcached but not necessarily on file cache. High-concurrency endpoints can slightly exceed the configured limit under file cache.
  • No time travel. Because limits are cache-TTL based, tests generally need short windows or real sleeps; Carbon::setTestNow() will not make cache entries expire. Use a short decay and flush between tests.
  • Exclude operational endpoints. Health checks, readiness probes, webhooks, and static assets should be outside the throttled group, otherwise your monitoring or payment provider will hit 429s.
  • Watch the 429 response contract. If clients do not receive Retry-After or X-RateLimit-* headers, they will retry blindly and make the problem worse. Add those headers in your own wrapper if the package omits them.
  • Do not patch vendor/. If you need different keying or response behavior, subclass or reimplement the middleware in app/ and bind the alias to your class. That survives composer install and makes the eventual migration to framework rate limiting straightforward.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource