abr4xas/cache-version-laravel is a lightweight helper around Laravel's cache system that automatically versions cache keys behind a human-friendly prefix. That lets you invalidate entire groups of cached data without touching individual keys or writing custom eviction logic—perfect for paginated feeds, dashboards, and expensive queries.
- PHP 8.4 or later
- Laravel Framework 12.37 or later
Install via Composer:
composer require abr4xas/cache-version-laravelThe package registers its service provider automatically thanks to Laravel Package Discovery, so no additional setup is required.
Every cache entry is stored using the following pattern:
<prefix>:v<version>:<key>
- Prefix — A logical namespace for a group of cached values.
- Version — An auto-incremented integer stored in cache to invalidate the entire prefix.
- Key — Whatever identifier you need underneath the prefix.
When you call flush('prefix'), the version increments and all previously stored entries become unreachable without needing to manually delete any keys.
use Abr4xas\CacheVersionedLaravel\Facade\CacheVersioned as VersionedCache;
use App\Models\Post;
use App\Models\Setting;
// 1️⃣ Basic usage with TTL (seconds or DateInterval)
$posts = VersionedCache::remember(
'angel_cruz_cache_blog_page',
'posts:page:1',
3600,
fn () => Post::latest()->paginate(10)
);
// 2️⃣ Cache forever without a TTL
$settings = VersionedCache::rememberForever(
'site_settings',
'home_page',
fn () => Setting::all()->pluck('value', 'key')
);
// 3️⃣ Invalidate an entire prefix instantly
VersionedCache::flush('angel_cruz_cache_blog_page');
// 4️⃣ Use a specific cache store for an operation
$pageNine = VersionedCache::remember(
'angel_cruz_cache_blog_page',
'posts:page:9',
3600,
fn () => Post::latest()->paginate(10),
store: 'array_secondary' // or 'file', 'redis', 'database', etc.
);If you prefer dependency injection, resolve the service from the container:
use Abr4xas\CacheVersionedLaravel\CacheVersioned;
class DashboardController
{
public function __construct(
private CacheVersioned $cache
) {}
public function __invoke()
{
return $this->cache->remember('dashboard', 'stats', 600, function () {
// Heavy aggregation work...
});
}
}put(string $prefix, string $key, mixed $value, DateInterval|DateTimeInterface|int|null $ttl = null, ?string $store = null): boolget(string $prefix, string $key, mixed $default = null, ?string $store = null): mixedforget(string $prefix, string $key, ?string $store = null): boolflush(string $prefix, ?string $store = null): intremember(string $prefix, string $key, DateInterval|DateTimeInterface|int|null $ttl, callable $callback, ?string $store = null): mixedrememberForever(string $prefix, string $key, callable $callback, ?string $store = null): mixedversion(string $prefix, ?string $store = null): intsetVersion(string $prefix, int $version, ?string $store = null): boolreset(string $prefix, ?string $store = null): bool
All methods accept an optional $store argument, allowing you to switch cache drivers per call without touching your business logic.
The repository includes a Pest test suite that exercises the full API surface, façade integration, and per-store isolation:
composer testThe test suite uses Orchestra Testbench with in-memory cache drivers, so it runs without external services.
- Prefix consistently — Use descriptive prefixes (e.g.,
blog_posts,user_profile:{$userId}) to control invalidation boundaries precisely. - Flush selectively — Prefer
flush()over manual key removal to keep your code succinct and less error-prone. - Custom stores — Use per-call stores for long-lived caches (e.g., Redis) while keeping defaults on faster transient drivers.
- Observe versions —
version()is handy for debugging and for exposing cache state in observability dashboards.
- Fork the repository.
- Install dependencies with
composer install. - Run
composer testto ensure the suite passes. - Open a pull request describing your change.
Please feel free to submit issues or enhancements. Contributions are welcome!
The MIT License (MIT). Refer to the LICENSE file for more information.