Laravel Cooldown: Per-Action Waiting Periods | Mohamed Said        [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://msaied.com) [ Home ](https://msaied.com) [ Projects ](https://msaied.com/projects) [ Articles  ](https://msaied.com/articles) [ Certificates ](https://msaied.com/certificates) [ Contact ](https://msaied.com#contact-section) 

       [  ](https://github.com/EG-Mohamed)       

 [ Home ](https://msaied.com) [ Projects ](https://msaied.com/projects) [ Articles ](https://msaied.com/articles) [ Certificates ](https://msaied.com/certificates) [ Contact ](https://msaied.com#contact-section) 

  [ home ](https://msaied.com)    [ articles ](https://msaied.com/articles)    Enforce Per-Action Waiting Periods in Laravel with the Cooldown Package        On this page       1. [  What Is Laravel Cooldown? ](#what-is-laravel-cooldown)
2. [  Key Features at a Glance ](#key-features-at-a-glance)
3. [  The Fluent API ](#the-fluent-api)
4. [  Atomic Blocking ](#atomic-blocking)
5. [  Cooldowns on Eloquent Models ](#cooldowns-on-eloquent-models)
6. [  Route Middleware ](#route-middleware)
7. [  Storage Backends ](#storage-backends)
8. [  Installation ](#installation)
9. [  Real Takeaways ](#real-takeaways)

  ![Enforce Per-Action Waiting Periods in Laravel with the Cooldown Package](https://cdn.msaied.com/432/a8a830b45119cc7fafc7e27d7951e114.png)

 [  Laravel ](https://msaied.com/articles?category=laravel) [  Composer Pacakge ](https://msaied.com/articles?category=composer-pacakge)  #Laravel   #Packages   #Rate Limiting   #Cooldown   #PHP  

 Enforce Per-Action Waiting Periods in Laravel with the Cooldown Package 
=========================================================================

     16 Jul 2026      4 min read    ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said  

       Table of contents

  9 sections  

1. [  01   What Is Laravel Cooldown?  ](#what-is-laravel-cooldown)
2. [  02   Key Features at a Glance  ](#key-features-at-a-glance)
3. [  03   The Fluent API  ](#the-fluent-api)
4. [  04   Atomic Blocking  ](#atomic-blocking)
5. [  05   Cooldowns on Eloquent Models  ](#cooldowns-on-eloquent-models)
6. [  06   Route Middleware  ](#route-middleware)
7. [  07   Storage Backends  ](#storage-backends)
8. [  08   Installation  ](#installation)
9. [  09   Real Takeaways  ](#real-takeaways)

       What Is Laravel Cooldown?
-------------------------

Laravel Cooldown is a package by [Mahedi Zaman Zaber](https://github.com/zaber-dev) that enforces per-action waiting periods in your Laravel application. While Laravel's built-in `RateLimiter` counts how many requests hit an endpoint within a window, Cooldown answers a different question: *is this specific action still within its waiting period for this specific owner?* That distinction matters for flows like OTP resends, password reset requests, or payment retries, where you care about the gap between attempts rather than a raw request count.

Key Features at a Glance
------------------------

- **Owner-scoped actions** — scope a cooldown to a model, an IP string, or nothing for a global lock
- **`HasCooldowns` trait** — attach `$user->cooldown('action')` directly to any Eloquent model
- **Route middleware** — `cooldown:action,duration` with an optional driver argument
- **Atomic `block()`** — acquires a lock, runs the callback, and sets the cooldown only on success
- **`enforce()`** — throws `CooldownActiveException`, rendered as HTTP 429
- **`CooldownInfo` object** — exposes `remainingSeconds()` and `remainingForHumans()`
- **Cache and database backends** — switchable per call; database backend survives cache flushes
- **Pruning** — expired database rows cleared via Laravel's `model:prune` command

The Fluent API
--------------

A cooldown is a named action, an optional owner, and a duration:

```php
use ZaberDev\Cooldown\Facades\Cooldown;

// Global lock for 10 minutes
Cooldown::for('rebuild_search_index')->for(600);

// User-scoped lock for 15 minutes
Cooldown::for('resend_verification', $user)->for(900);

// Lock until end of day
Cooldown::for('daily_checkin', $user)->until(now()->endOfDay());

```

When a cooldown is active, `info()` returns a `CooldownInfo` object:

```php
if (Cooldown::for('resend_verification', $user)->active()) {
    $info = Cooldown::for('resend_verification', $user)->info();
    echo "Please wait " . $info->remainingForHumans() . " before requesting another email.";
}

```

To stop a request outright instead of branching, call `enforce()`:

```php
Cooldown::for('request_password_reset', $user)->enforce();

```

Atomic Blocking
---------------

Race conditions are the classic problem with cooldowns: two concurrent requests can both pass the active check before either one sets the lock. `block()` solves this by acquiring an atomic lock, running the callback, and only applying the cooldown if the work succeeds:

```php
Cooldown::for('send_login_code', $user)->block(function () use ($smsClient, $user) {
    $smsClient->sendCode($user->phone);
}, duration: 90);

```

Cooldowns on Eloquent Models
----------------------------

Add the `HasCooldowns` trait to any model and the same fluent builder becomes available directly on the instance:

```php
use ZaberDev\Cooldown\HasCooldowns;

class User extends Authenticatable
{
    use HasCooldowns;
}

$user->cooldown('change_avatar')->for(300);

if ($user->cooldown('change_avatar')->active()) {
    return response()->json(['message' => 'You can change your avatar again shortly.'], 429);
}

$user->cooldown('change_avatar')->reset();

```

On the database backend, records are polymorphic, so you can query a model's cooldowns like any relation:

```php
$activeCooldowns = $user->cooldowns()->where('expires_at', '>', now())->get();

```

Route Middleware
----------------

```php
Route::post('/feedback', [FeedbackController::class, 'store'])
    ->middleware('cooldown:submit_feedback,120');

Route::post('/invoices/export', [InvoiceController::class, 'export'])
    ->middleware('cooldown:invoice_export,600,database');

```

Storage Backends
----------------

The default driver is `cache` (Redis or Memcached). Switch to `database` when the lock must survive a cache flush—billing flows being the obvious example:

```php
Cooldown::for('renew_subscription', $user)->using('database')->for(86400);

```

Custom drivers can be registered via `Cooldown::extend()` in a service provider.

Installation
------------

Requires PHP 8.2 and supports Laravel 11, 12, and 13:

```bash
composer require zaber-dev/laravel-cooldown
php artisan vendor:publish --provider="ZaberDev\Cooldown\CooldownServiceProvider"
php artisan migrate

```

Configuration lives in `config/cooldown.php` and covers the default driver, cache store, key prefix, table name, and event dispatching.

Real Takeaways
--------------

- Cooldown complements `RateLimiter`—use it when the *gap between attempts* matters more than a request count.
- `block()` is the right tool for any action where a race condition could fire duplicate side effects.
- The database backend is worth the extra write cost for anything tied to billing or compliance.
- The `HasCooldowns` trait keeps model-scoped logic clean and avoids scattering `Cooldown::for($user)` calls everywhere.
- Pruning expired rows with `model:prune` keeps the `cooldowns` table lean without custom maintenance scripts.

---

*Source: [Enforce Per-Action Waiting Periods in Laravel with Cooldown — Laravel News](https://laravel-news.com/enforce-per-action-waiting-periods-in-laravel-with-cooldown)*

 Found this useful?

          [  ](https://twitter.com/intent/tweet?url=https%3A%2F%2Fmsaied.com%2Farticles%2Fenforce-per-action-waiting-periods-in-laravel-with-the-cooldown-package&text=Enforce+Per-Action+Waiting+Periods+in+Laravel+with+the+Cooldown+Package) [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fmsaied.com%2Farticles%2Fenforce-per-action-waiting-periods-in-laravel-with-the-cooldown-package) 

 Frequently Asked Questions 
----------------------------

  3 questions  

     Q01  How is Laravel Cooldown different from Laravel's built-in RateLimiter?        RateLimiter counts how many requests hit an endpoint within a time window. Cooldown tracks whether a specific named action for a specific owner is still within its waiting period—useful when you care about the gap between attempts rather than a raw request count. 

      Q02  How does the block() method prevent race conditions?        block() acquires an atomic lock before running the callback and only sets the cooldown if the callback succeeds. This prevents two concurrent requests from both passing the active check before either one sets the lock. 

      Q03  When should I use the database backend instead of the cache backend?        Use the database backend when the cooldown lock must survive a cache flush—for example, billing flows or subscription renewals where losing the lock state could allow duplicate charges. 

  Continue reading

 More Articles 
---------------

 [ View all    ](https://msaied.com/articles) 

 [ ![Livewire v3 Performance: Lazy Hydration, Computed Properties, and Minimising Wire Payloads](https://cdn.msaied.com/431/5931d6ca41b721bc1cd98ccc4ce063c7.png) livewire laravel performance 

### Livewire v3 Performance: Lazy Hydration, Computed Properties, and Minimising Wire Payloads

Practical techniques for keeping Livewire v3 components fast: lazy hydration, memoised computed properties, ta...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 16 Jul 2026     4 min read  

  Read    

 ](https://msaied.com/articles/livewire-v3-performance-lazy-hydration-computed-properties-and-minimising-wire-payloads) [ ![Filament v5 Preview: Schema Unification, Performance Shifts, and How to Prepare](https://cdn.msaied.com/430/44b6a4ac9fef052463a7ca8318fe463e.png) filament laravel filament-v5 

### Filament v5 Preview: Schema Unification, Performance Shifts, and How to Prepare

Filament v5 is reshaping how panels, forms, and tables are composed. This deep-dive covers the confirmed archi...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 16 Jul 2026     4 min read  

  Read    

 ](https://msaied.com/articles/filament-v5-preview-schema-unification-performance-shifts-and-how-to-prepare-1) [ ![Build a Laravel Scout Search Endpoint With the HTTP QUERY Method](https://cdn.msaied.com/433/f1100f27bf9bb41032e0ea927629e818.png) Laravel Laravel Scout HTTP QUERY 

### Build a Laravel Scout Search Endpoint With the HTTP QUERY Method

Learn how to register an HTTP QUERY route in Laravel 13 using Route::match(), back it with Laravel Scout's dat...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 16 Jul 2026     3 min read  

  Read    

 ](https://msaied.com/articles/build-a-laravel-scout-search-endpoint-with-the-http-query-method) 

   [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://msaied.com)Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

Explore

- [Home](https://msaied.com)
- [Projects](https://msaied.com/projects)
- [Articles](https://msaied.com/articles)
- [Certificates](https://msaied.com/certificates)
- [Contact](https://msaied.com#contact-section)

Connect

- [   hello@msaied.com ](mailto:hello@msaied.com)
- [   +20 109 461 9204 ](tel:+201094619204)

© 2026 Mohamed Said. All rights reserved.

 [  ](https://github.com/EG-Mohamed) [  ](https://www.linkedin.com/in/msaiedm/) [  ](https://wa.me/201094619204) [  ](mailto:hello@msaied.com) [  ](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
