PHPackages                             jeffersongoncalves/laravel-page-cache - 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. [Caching](/categories/caching)
4. /
5. jeffersongoncalves/laravel-page-cache

ActiveLibrary[Caching](/categories/caching)

jeffersongoncalves/laravel-page-cache
=====================================

This Laravel package provides a full-page response cache middleware for stateless public GET pages. It caches 200 responses keyed by a version token, locale, and theme cookie, skips authenticated requests, exposes an X-Page-Cache HIT/MISS header, and offers a static flush() helper to invalidate every cached page at once.

v1.1.0(1mo ago)158MITPHPPHP ^8.2CI passing

Since Jun 20Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/jeffersongoncalves/laravel-page-cache)[ Packagist](https://packagist.org/packages/jeffersongoncalves/laravel-page-cache)[ Docs](https://github.com/jeffersongoncalves/laravel-page-cache)[ GitHub Sponsors](https://github.com/jeffersongoncalves)[ RSS](/packages/jeffersongoncalves-laravel-page-cache/feed)WikiDiscussions master Synced 2w ago

READMEChangelog (3)Dependencies (6)Versions (5)Used By (0)

[![Laravel Page Cache](https://raw.githubusercontent.com/jeffersongoncalves/laravel-page-cache/master/art/jeffersongoncalves-laravel-page-cache.png)](https://raw.githubusercontent.com/jeffersongoncalves/laravel-page-cache/master/art/jeffersongoncalves-laravel-page-cache.png)

Laravel Page Cache
==================

[](#laravel-page-cache)

[![Latest Version on Packagist](https://camo.githubusercontent.com/ae65c1e7b8900292133021bc352dc0963c49a36863cf2348b94fdcc90df13c91/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6a6566666572736f6e676f6e63616c7665732f6c61726176656c2d706167652d63616368652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/jeffersongoncalves/laravel-page-cache)[![GitHub Tests Action Status](https://camo.githubusercontent.com/596b76e422a9df9a243e9c7a641a6975ef2434f80e0177b8927a7ef0090ca6aa/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6a6566666572736f6e676f6e63616c7665732f6c61726176656c2d706167652d63616368652f72756e2d74657374732e796d6c3f6272616e63683d6d6173746572266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/jeffersongoncalves/laravel-page-cache/actions?query=workflow%3Arun-tests+branch%3Amaster)[![GitHub Code Style Action Status](https://camo.githubusercontent.com/406a05092bc12736bd0e78c22ed4d1cd26706d8d0f3c99c8a67b0a8cd140d141/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6a6566666572736f6e676f6e63616c7665732f6c61726176656c2d706167652d63616368652f6669782d7068702d636f64652d7374796c652d6973737565732e796d6c3f6272616e63683d6d6173746572266c6162656c3d636f64652532307374796c65267374796c653d666c61742d737175617265)](https://github.com/jeffersongoncalves/laravel-page-cache/actions?query=workflow%3A%22Fix+PHP+code+styling%22+branch%3Amaster)[![Total Downloads](https://camo.githubusercontent.com/270057723e8ea2ecee9262a4426d764ceeda95a0a473c453df29737fc75345b8/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6a6566666572736f6e676f6e63616c7665732f6c61726176656c2d706167652d63616368652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/jeffersongoncalves/laravel-page-cache)

This Laravel package provides a full-page response cache middleware for stateless public GET pages. It caches 200 responses keyed by a version token, locale, and theme cookie, skips authenticated requests, exposes an `X-Page-Cache` HIT/MISS header, and offers a static `flush()` helper to invalidate every cached page at once.

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

[](#installation)

You can install the package via composer:

```
composer require jeffersongoncalves/laravel-page-cache
```

You can publish the config file with:

```
php artisan vendor:publish --tag="laravel-page-cache-config"
```

This is the contents of the published config file:

```
return [
    'enabled' => env('PAGE_CACHE_ENABLED', true),

    // A TTL of 0 (or below) means "cache forever".
    'ttl' => (int) env('PAGE_CACHE_TTL', 3600),

    // Fold a normalized query string into the cache key (safe default).
    'include_query_string' => env('PAGE_CACHE_INCLUDE_QUERY_STRING', true),

    'key' => [
        'locale' => true,

        // Vary the cache on the negotiated content encoding.
        'accept_encoding' => true,

        'theme' => [
            'enabled' => true,
            'cookie' => 'theme',
        ],
    ],
];
```

Usage
-----

[](#usage)

Register `CachePublicPage` **after** `StartSession` and the authentication middleware — i.e. inside your `web` middleware group, not as the outermost middleware. The cache deliberately depends on a started session to tell guests from authenticated users, and registering it before `StartSession` would make it bail out on every request:

```
use Illuminate\Support\Facades\Route;
use JeffersonGoncalves\PageCache\Middleware\CachePublicPage;

Route::middleware(['web', CachePublicPage::class])->group(function () {
    Route::get('/', HomeController::class);
    Route::get('/{slug}', ShowController::class);
});
```

The first request to a path is computed normally and stored with an `X-Page-Cache: MISS` header. Subsequent requests are served straight from the cache with an `X-Page-Cache: HIT` header. Only stateless `GET` requests that return a `200` response from a guest (unauthenticated) visitor are cached, and the full response header bag (minus `Set-Cookie`) is replayed on a cache hit.

### What is never cached (important)

[](#what-is-never-cached-important)

To avoid leaking per-visitor state across visitors, the middleware **passes the request through untouched** (no read, no write) when any of the following is true:

- the request is authenticated (`$request->user()` is not `null`);
- there is no started session (so register it **after** `StartSession`);
- the response sets its own cookies (`Set-Cookie`);
- the response sends `Cache-Control: no-store`.

`Cache-Control: no-store` is the explicit opt-out you should reach for whenever a page renders per-visitor state. (Only `no-store` is honoured: Symfony stamps the default `Cache-Control: no-cache, private` on every response that does not set its own cache headers, so `no-cache`/`private` cannot be used as opt-out signals without disabling the cache for every page.)

> **Session/CSRF limitation — read this.** Laravel flushes queued cookies (the session cookie, `XSRF-TOKEN`, flash data) into the response **after** this middleware has already inspected it, so the `Set-Cookie` guard above cannot see them. A page that embeds a `@csrf` token in a `` therefore looks cacheable, and caching it would replay one visitor's CSRF token to everyone else. **Any response that contains a CSRF token, a form, flash messages, or other guest-session content must mark itself with `Cache-Control: no-store`** (e.g. `return response($html)->header('Cache-Control', 'no-store');`) or be kept out of the cached route group entirely. There is no reliable way for the middleware to detect this for you.

### Invalidating the cache

[](#invalidating-the-cache)

Call `CachePublicPage::flush()` from your model observers to invalidate every cached page whenever the underlying content changes:

```
use JeffersonGoncalves\PageCache\Middleware\CachePublicPage;

class ProjectObserver
{
    public function saved(Project $project): void
    {
        CachePublicPage::flush();
    }

    public function deleted(Project $project): void
    {
        CachePublicPage::flush();
    }
}
```

`flush()` bumps an internal version token, so every previously cached page is bypassed on the next request without touching individual cache keys.

### Cache key

[](#cache-key)

By default the cache key is composed of the version token, the current locale, the negotiated `Accept-Encoding`, the theme cookie value, a hash of the request path, and a hash of a normalized (sorted) query string. You can disable the locale, `accept_encoding`, or theme segments — or change the theme cookie name — through the config file. The `Accept-Encoding` segment is normalized (tokens lowercased and sorted) so a body compressed for a gzip/br client is never replayed to a client that cannot decode it.

The path (not the full URL) is used for the path segment, and the query string is normalized and hashed separately so that `?b=2&a=1` and `?a=1&b=2` collapse to the same entry while `/products?page=2` stays distinct from `/products?page=1`. If a route ignores the query string entirely you can drop it from the key by setting `include_query_string` to `false`.

Testing
-------

[](#testing)

```
composer test
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

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

[](#contributing)

Please see [CONTRIBUTING](.github/CONTRIBUTING.md) for details.

Security Vulnerabilities
------------------------

[](#security-vulnerabilities)

Please review [our security policy](../../security/policy) on how to report security vulnerabilities.

Credits
-------

[](#credits)

- [Jèfferson Gonçalves](https://github.com/jeffersongoncalves)
- [All Contributors](../../contributors)

License
-------

[](#license)

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

###  Health Score

43

—

FairBetter than 89% of packages

Maintenance91

Actively maintained with recent releases

Popularity13

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 92.3% 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 ~0 days

Total

3

Last Release

44d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/411493?v=4)[Jefferson Gonçalves](/maintainers/jeffersongoncalves)[@jeffersongoncalves](https://github.com/jeffersongoncalves)

---

Top Contributors

[![jeffersongoncalves](https://avatars.githubusercontent.com/u/411493?v=4)](https://github.com/jeffersongoncalves "jeffersongoncalves (12 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (1 commits)")

---

Tags

cachecomposerjeffersongoncalveslaravellaravel-packagemiddlewarepage-cacheperformancephplaraveljeffersongoncalveslaravel-page-cache

###  Code Quality

TestsPest

Static AnalysisPHPStan

### Embed Badge

![Health badge](/badges/jeffersongoncalves-laravel-page-cache/health.svg)

```
[![Health](https://phpackages.com/badges/jeffersongoncalves-laravel-page-cache/health.svg)](https://phpackages.com/packages/jeffersongoncalves-laravel-page-cache)
```

###  Alternatives

[spatie/laravel-medialibrary

Associate files with Eloquent models

6.2k45.4M679](/packages/spatie-laravel-medialibrary)[spatie/laravel-responsecache

Speed up a Laravel application by caching the entire response

2.8k9.3M72](/packages/spatie-laravel-responsecache)[spatie/laravel-health

Monitor the health of a Laravel application

88212.7M180](/packages/spatie-laravel-health)[harris21/laravel-fuse

Circuit breaker for Laravel queue jobs. Protect your workers from cascading failures.

24773.9k](/packages/harris21-laravel-fuse)[defstudio/telegraph

A laravel facade to interact with Telegram Bots

817336.8k3](/packages/defstudio-telegraph)[nativephp/mobile

NativePHP for Mobile

1.1k102.1k123](/packages/nativephp-mobile)

PHPackages © 2026

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