Building a Driver-Based Cooldown Manager for Laravel
DEV Community

Building a Driver-Based Cooldown Manager for Laravel

Most Laravel applications eventually need some form of cooldown. Not request throttling-but actual action cooldowns. Examples include:

  • Password reset requests
  • Email verification
  • OTP / SMS sending
  • AI prompt generation
  • Report exports
  • Payment retries
  • Reward claiming
  • Expensive background jobs

Laravel already provides an excellent RateLimiter, but it's primarily designed for request throttling (for example, "60 requests per minute"). When I was building an application, I found myself needing something slightly different:

  • Persist cooldowns in either cache or database
  • Attach cooldowns directly to Eloquent models
  • Reuse the same API across controllers, jobs, commands, and middleware
  • Store cooldowns for arbitrary targets such as Users, API tokens, IP addresses, or custom identifiers
  • Allow switching storage drivers without changing application code

That led me to build Laravel Cooldown.

The Goal

I wanted an API that was expressive enough to read almost like English.

Cooldown::for('password_reset', $user)->enforce();

// Perform the action...

Cooldown::for('password_reset', $user)->for(300);

Checking a cooldown is equally straightforward:

if (Cooldown::for('password_reset', $user)->active()) {
    $remaining = Cooldown::for('password_reset', $user)
        ->info()
        ->remainingSeconds();
}

Some Design Decisions

Rather than coupling everything to a single storage implementation, the package uses Laravel's Illuminate\Support\Manager to provide interchangeable drivers. Currently it supports:

  • Cache
  • Database

Additional drivers can be registered using Laravel's familiar extend() pattern.

Another design decision was to support Eloquent models as first-class cooldown targets. Instead of manually generating cache keys, you can simply write:

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

The package automatically resolves unique keys for models, scalars, IP addresses, and other supported targets.

Middleware That Only Starts on Success

One small behavior that bothered me with many cooldown implementations is that they start counting down before the request has actually succeeded. Imagine submitting a form that fails validation. You shouldn't have to wait another minute just because you mistyped your email address.

The middleware in Laravel Cooldown only creates the cooldown after successful (2xx) or redirected (3xx) responses.

Features

  • Cache and Database drivers
  • Expressive fluent API
  • Native Eloquent integration
  • Route middleware
  • Immutable DTOs
  • Event dispatching
  • Automatic database pruning
  • Custom driver support

Feedback Welcome

This is an open-source project, and I'd really appreciate feedback from the Laravel community. If you have suggestions for the API, architecture, or documentation-or ideas for additional drivers or features-I'd love to hear them.

GitHub: https://github.com/zaber-dev/laravel-cooldown

Comments

No comments yet. Start the discussion.