PHPackages                             zaber-dev/laravel-lock - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. zaber-dev/laravel-lock

ActiveLibrary[Database &amp; ORM](/categories/database)

zaber-dev/laravel-lock
======================

Application-level distributed locking for Laravel with Eloquent integration, middleware, automatic owner detection, and cache/database storage.

v1.0.1(1mo ago)618↓50%1MITPHPPHP ^8.2CI passing

Since Jul 10Pushed 1mo agoCompare

[ Source](https://github.com/zaber-dev/laravel-lock)[ Packagist](https://packagist.org/packages/zaber-dev/laravel-lock)[ RSS](/packages/zaber-dev-laravel-lock/feed)WikiDiscussions main Synced 2w ago

READMEChangelog (2)Dependencies (12)Versions (3)Used By (0)

 [![Laravel Lock Banner](art/header.png)](art/header.png)

Laravel Lock
============

[](#laravel-lock)

[![Latest Version on Packagist](https://camo.githubusercontent.com/1e4c263c7293904a053b8b80f20b4fa8717f5bfc5048de49bd8ab1ba2f084214/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7a616265722d6465762f6c61726176656c2d6c6f636b2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/zaber-dev/laravel-lock)[![Run Tests](https://camo.githubusercontent.com/3f11c74026cad60909b2ccc004dbf544a27d5a41229582c49808adcc8876b394/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f7a616265722d6465762f6c61726176656c2d6c6f636b2f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/zaber-dev/laravel-lock/actions/workflows/run-tests.yml)[![Total Downloads](https://camo.githubusercontent.com/8a15f7a4b217473a0de18af8f777122c1a9e8d429c667a34801a68e77773e4bc/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f7a616265722d6465762f6c61726176656c2d6c6f636b2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/zaber-dev/laravel-lock)[![PHP Version Require](https://camo.githubusercontent.com/c206c16779613a9898dd4805a900e9c087c79135773cb3769a5648609af366f4/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f646570656e64656e63792d762f7a616265722d6465762f6c61726176656c2d6c6f636b2f7068702e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/zaber-dev/laravel-lock)[![License](https://camo.githubusercontent.com/9b033a7eada2b99309ac8176f98aafb231a15b9812442e7b280bfeba28ff9232/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f7a616265722d6465762f6c61726176656c2d6c6f636b2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/zaber-dev/laravel-lock)

**Supports:** Laravel 11, 12 &amp; 13+ • PHP 8.2+ • Redis • Memcached • Database

**Application-level distributed locking for Laravel.** Prevent race conditions and concurrent execution across actions, workflows, and endpoints with automatic owner detection and cleanup.

Manage locks using cache or persistent database storage, attach them to Eloquent models, protect routes with middleware, and automatically track ownership — all through a clean, expressive API.

> Unlike Laravel's low-level `Cache::lock()`, Laravel Lock elevates distributed locking into a first-class, entity-scoped application abstraction (`Lock::for(...)`) with owner detection and lifecycle events.

---

Quick Example
-------------

[](#quick-example)

```
// Option 1: High-level atomic block execution (acquires lock + executes + auto-releases in finally)
Lock::for('billing_charge', $user)
    ->block(function () {
        // Critical section...
    });

// Option 2: Step-by-step acquisition and release with automatic owner detection
if (Lock::for('billing_charge', $user)
        ->ttl(60)
        ->acquire()) {
    try {
        // Do work...
    } finally {
        Lock::for('billing_charge', $user)->release();
    }
}
```

---

Common Use Cases
----------------

[](#common-use-cases)

Laravel Lock is ideal for:

- Preventing duplicate payment processing
- Serializing inventory allocation and order checkout pipelines
- Protecting high-concurrency webhook processing endpoints
- Ensuring single-instance background cron job execution
- Preventing race conditions during financial account balance transfers
- Coordinating distributed microservice operations
- Preventing simultaneous document edits

---

Why not Cache::lock()?
----------------------

[](#why-not-cachelock)

Laravel's `Cache::lock()` is an excellent low-level primitive for atomic locking.

**Laravel Lock doesn't replace `Cache::lock()`**. Instead, it builds on the same concept while providing higher-level application primitives for common Laravel workflows. Laravel Lock focuses on application-level locking with:

- **Automatic owner resolution** (`user_id`, queue job ID, or request hash)
- **Eloquent model integration** (`$user->lock('billing_charge')->acquire()`)
- **Route middleware** (`lock:billing_charge,30`)
- **Interchangeable storage backends** (Cache &amp; persistent Database)
- **Rich lifecycle events** (`LockAcquired`, `LockReleased`, `LockFailed`)
- **Immutable DTOs** (`LockInfo` with strict date math)
- **Polymorphic target resolution** (Models, strings, integers)
- **Automatic database pruning** (`model:prune`)
- **High-level fluent API** (`Lock::for('action', $target)->ttl(60)->acquire()`)

---

Why Laravel Lock?
-----------------

[](#why-laravel-lock)

While `Cache::lock()` handles basic mutex acquisition, **Laravel Lock** is engineered for entity-scoped, application-level mutual exclusion across your entire Laravel ecosystem.

FeatureCache::lock()Laravel Lock**Primary Purpose**Low-level atomic mutex**Application-level distributed locking****High-Level Fluent API** (`Lock::for()->ttl()`)❌ Manual✅ **Expressive &amp; Clean (`Lock::for()`)****Automatic Owner Resolution**❌ Manual Token✅ **Built-in (`user_id`, job, hash)****First-Class Eloquent Integration** (`$user->lock()`)❌✅ **Native (`HasLocks`)****Persistent Database Storage**❌ Cache Only✅ **Both Cache &amp; Database Supported****Success-Only / Auto-Release Route Middleware**❌✅ **Built-in (`RequireLock`)****Polymorphic Target Scoping**❌ Manual Keys✅ **Automatic Key Mapping****Immutable DTOs (`LockInfo`)**❌✅ **Strict (`CarbonImmutable`)****Automatic Database Pruning** (`model:prune`)N/A✅ **Built-in (`Prunable`)****Custom Storage Extensibility** (`Lock::extend()`)❌✅ **Closure / Container****Event Dispatching** (`LockAcquired` / `Released`)❌✅ **Configurable Events**---

Features
--------

[](#features)

- **Automatic Owner Detection**: Generates and tracks unique ownership tokens automatically (`user_id`, job ID, or request hash) to ensure threads only release locks they actually own.
- **Expressive Fluent API**: Chain expressive calls like `Lock::for('process_payout', $user)->ttl(120)->acquire()`.
- **Native Eloquent Integration**: Attach the `HasLocks` trait to any model for scoped lock management (`$user->lock('billing_charge')->acquire()`).
- **Route Middleware**: Protect endpoints automatically using `lock:action_name,duration_in_seconds` with automatic HTTP `429` enforcement and `finally` auto-release cleanup.
- **Multiple Storage Backends** (Cache &amp; Database): Choose lightweight fast cache stores (Redis, Memcached, Array) or persistent database-backed locks with automatic cleanup.
- **Immutable DTOs**: Work safely with strict `LockInfo` Data Transfer Objects returning precise metadata (`key`, `owner`, `expiresAt`, `isExpired()`).
- **Custom Storage Extensibility**: Register custom storage drivers on the fly with closure-based creators via `Lock::extend()`.
- **Prunable Database Storage**: Built-in `Prunable` trait integration ensures expired database lock records never clutter your database.

---

Documentation
-------------

[](#documentation)

- [Installation](#installation)
- [Configuration](#configuration)
- [Usage Guide](#usage-guide)
- [LEARN.md](LEARN.md)

---

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

[](#installation)

Ready to get started? Install the package with Composer:

```
composer require zaber-dev/laravel-lock
```

Publish the configuration and database migrations:

```
php artisan vendor:publish --provider="ZaberDev\Lock\LockServiceProvider"
```

Run migrations if you intend to use the `database` driver:

```
php artisan migrate
```

---

Configuration
-------------

[](#configuration)

The configuration file `config/locks.php` allows you to define your default storage engine, driver parameters, and event dispatching behaviors:

```
return [
    /*
    |--------------------------------------------------------------------------
    | Default Lock Driver
    |--------------------------------------------------------------------------
    |
    | Supported drivers: "cache", "database"
    |
    */
    'default' => env('LOCK_DRIVER', 'cache'),

    'drivers' => [
        'cache' => [
            'driver' => 'cache',
            'store' => env('LOCK_CACHE_STORE', null),
            'prefix' => 'locks:',
        ],
        'database' => [
            'driver' => 'database',
            'table' => 'locks',
        ],
    ],

    'events' => [
        'dispatch' => true,
    ],
];
```

---

Usage Guide
-----------

[](#usage-guide)

### 1. The Fluent Lock API

[](#1-the-fluent-lock-api)

The `Lock` facade provides an expressive builder interface for acquiring, checking, blocking, and releasing locks.

#### Acquiring &amp; Checking a Lock

[](#acquiring--checking-a-lock)

```
use ZaberDev\Lock\Facades\Lock;

$builder = Lock::for('billing_charge', $user)
    ->ttl(60)
    ->owner('worker_abc'); // Optional: explicit override (defaults to automatic owner detection)

if ($builder->acquire()) {
    try {
        // Lock acquired, execute sensitive logic...
    } finally {
        $builder->release();
    }
} else {
    // Lock is currently held by someone else
}

// Check lock status
$isLocked = Lock::for('billing_charge', $user)->isLocked();
$info = Lock::for('billing_charge', $user)->info(); // LockInfo DTO
```

#### Atomic Block Execution (`block`)

[](#atomic-block-execution-block)

For operations vulnerable to concurrent execution bursts, use the `block()` helper. `block()` automatically acquires the lock, executes your callback, and safely releases the lock inside a `try...finally` block:

```
Lock::for('billing_charge', $user)->block(function () use ($stripeService, $user) {
    $stripeService->charge($user);
});
```

#### Force Releasing Locks

[](#force-releasing-locks)

If an administrative or recovery script needs to clear a locked resource regardless of owner:

```
Lock::for('billing_charge', $user)->forceRelease();
```

---

### 2. Eloquent Model Integration (`HasLocks`)

[](#2-eloquent-model-integration-haslocks)

Add the `HasLocks` trait to any Eloquent model to scope locks directly to that entity:

```
namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use ZaberDev\Lock\HasLocks;

class User extends Authenticatable
{
    use HasLocks;
}
```

You can now interact directly with your model instance:

```
$user = User::find(1);

// Acquire a 60-second lock on "billing_charge" for this user
if ($user->lock('billing_charge')->ttl(60)->acquire()) {
    try {
        // Charge user...
    } finally {
        $user->lock('billing_charge')->release();
    }
}

// Check status
if ($user->lock('billing_charge')->isLocked()) {
    return response()->json(['message' => 'Action locked.'], 429);
}
```

#### Polymorphic Database Querying

[](#polymorphic-database-querying)

When using the `database` driver, `HasLocks` also exposes a `locks()` polymorphic relationship, allowing direct querying and bulk management:

```
// Get all database lock records assigned to this user
$activeLocks = $user->locks()->where('expires_at', '>', now())->get();

// Delete all lock records for this user
$user->locks()->delete();
```

---

### 3. Route Middleware

[](#3-route-middleware)

Protect routes declaratively without writing boilerplate checks in your controllers using the `RequireLock` middleware:

```
use Illuminate\Support\Facades\Route;

// Enforce a 30-second lock on billing endpoints per User / IP address
Route::post('/billing/charge', [BillingController::class, 'charge'])
    ->middleware('lock:billing_charge,30');

// Use a specific storage engine
Route::post('/api/payout', [PayoutController::class, 'store'])
    ->middleware('lock:payout,60,database');
```

**How the Middleware Works:**

- Before executing your controller, `RequireLock` attempts to acquire a lock for the specified duration (`HTTP 429` if already locked).
- When your controller finishes executing (whether `2xx success`, `4xx validation error`, or `5xx exception`), the middleware automatically releases the lock in its `finally` block so subsequent requests can proceed without waiting for TTL expiration.

---

### 4. Working with Storage Backends (`using` &amp; `driver`)

[](#4-working-with-storage-backends-using--driver)

By default, the package uses the storage engine defined in `config/locks.php`. You can switch storage drivers on the fly per request or action:

```
// Store transient mutex checks in fast cache/Redis
Lock::for('api_sync', $ip)->using('cache')->ttl(15)->acquire();

// Store critical transaction locks inside persistent database tables
Lock::for('account_transfer', $user)->using('database')->ttl(120)->acquire();
```

#### Registering Custom Storage Drivers

[](#registering-custom-storage-drivers)

You can extend the `LockManager` with your own storage drivers (e.g., DynamoDB, Redis Cluster) in your `AppServiceProvider`:

```
use ZaberDev\Lock\Contracts\LockDriverContract;
use ZaberDev\Lock\Facades\Lock;

public function boot(): void
{
    Lock::extend('redis-cluster', function ($app) {
        return new MyRedisClusterLockDriver($app['redis']);
    });
}
```

---

### 5. Database Pruning (`Prunable`)

[](#5-database-pruning-prunable)

When using the `database` driver, expired records are automatically marked for pruning via Laravel's `Prunable` trait on the `ZaberDev\Lock\Models\LockModel` model.

To clean up old records automatically, schedule Laravel's `model:prune` command in your `console.php` or `Kernel.php`:

```
use Illuminate\Support\Facades\Schedule;
use ZaberDev\Lock\Models\LockModel;

Schedule::command('model:prune', ['--model' => LockModel::class])->daily();
```

---

### 6. Events

[](#6-events)

Whenever a lock is acquired, released, failed, or force-released, the package dispatches strongly typed events if enabled (`locks.events.dispatch = true`):

- **`ZaberDev\Lock\Events\LockAcquired`**: Dispatched when `acquire()` succeeds (`$key`, `$owner`, `$expiresAt`, `$info`).
- **`ZaberDev\Lock\Events\LockReleased`**: Dispatched when `release()` succeeds (`$key`, `$owner`).
- **`ZaberDev\Lock\Events\LockFailed`**: Dispatched when `acquire()` fails due to concurrent ownership (`$key`, `$owner`).
- **`ZaberDev\Lock\Events\LockForceReleased`**: Dispatched when `forceRelease()` clears a lock (`$key`).

You can listen to these in your `EventServiceProvider` for logging, monitoring, or alerting.

---

Related Packages
----------------

[](#related-packages)

This package is part of the **[ZaberDev Laravel Ecosystem](https://github.com/zaber-dev/laravel-ecosystem)** (Laravel Productivity Toolkit) — a cohesive suite of high-level application primitives engineered for concurrency, state management, and resource allocation.

Explore the complete directory of packages, detailed use cases, and documentation in our **[Ecosystem Index Hub](https://github.com/zaber-dev/laravel-ecosystem/blob/main/PACKAGES.md)**.

---

Testing &amp; Quality
---------------------

[](#testing--quality)

Run the comprehensive PHPUnit test suite locally:

```
composer test
```

---

Contributing
------------

[](#contributing)

Thank you for considering contributing! Please ensure any pull requests include thorough PHPUnit tests covering unit, feature, and driver integration scenarios.

---

License
-------

[](#license)

The MIT License (MIT). Please see [LICENSE.md](LICENSE.md) for more information.

---

 **Built with ❤️ as part of the ZaberDev Laravel Ecosystem.**

###  Health Score

43

—

FairBetter than 89% of packages

Maintenance92

Actively maintained with recent releases

Popularity15

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~9 days

Total

2

Last Release

38d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/4968461fc31f46ebbff1e3f457a4168b4fad50f9700feac218345dc887be56be?d=identicon)[zaber-dev](/maintainers/zaber-dev)

---

Top Contributors

[![zaber-dev](https://avatars.githubusercontent.com/u/88625958?v=4)](https://github.com/zaber-dev "zaber-dev (4 commits)")

---

Tags

concurrencydatabasedistributed-lockeloquentlaravellaravel-11laravel-12laravel-13laravel-packagelearnlockingmutexrace-conditionsredisconcurrencylaraveleloquentmutexrace conditionlockingdistributed-lock

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/zaber-dev-laravel-lock/health.svg)

```
[![Health](https://phpackages.com/badges/zaber-dev-laravel-lock/health.svg)](https://phpackages.com/packages/zaber-dev-laravel-lock)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3345.4M354](/packages/psalm-plugin-laravel)[laravel/cashier

Laravel Cashier provides an expressive, fluent interface to Stripe's subscription billing services.

2.5k31.8M163](/packages/laravel-cashier)[laravel/horizon

Dashboard and code-driven configuration for Laravel queues.

4.2k99.8M362](/packages/laravel-horizon)[laravel/ai

The official AI SDK for Laravel.

1.1k4.6M342](/packages/laravel-ai)[api-platform/laravel

API Platform support for Laravel

58190.1k21](/packages/api-platform-laravel)[cyrildewit/eloquent-viewable

A minimalistic analytics package for Laravel with seamless view tracking for Eloquent models

8881.2M9](/packages/cyrildewit-eloquent-viewable)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
