Caching
Learn how to cache your application safely.
Many Laravel applications sit behind a shared cache, such as a CDN, a reverse proxy, or Varnish, to serve pages fast. This guide explains how to keep that performance without serving one visitor’s personalized content to another.
The problem with shared caches
A shared cache stores one copy of a response and serves it to everyone. That is what you want for pages that look the same for all visitors, but it is unsafe for personalized pages. If a visitor’s tailored content were stored in a shared cache, the next visitor would receive it too.
The package prevents this automatically. Whenever a response depends on the visitor, because you fetched personalized content, evaluated a query, or identified the user, the package marks it private so shared caches skip it. Responses that render only static content stay cacheable.
This relies on your cache honoring the standard Cache-Control: private directive, which CDNs and reverse proxies respect by default. If yours is configured to ignore it or to force caching, exclude personalized responses first.
Choosing an approach
When a page needs personalization, you have two options depending on whether you want to keep it in the shared cache:
| Personalize on the server | Personalize on the client | |
|---|---|---|
| Final content on first load | ||
| No content flicker | ||
| Visible to crawlers | ||
| Page stored in a shared cache |
Personalizing on the server gives the best experience, while personalizing on the client lets the page stay in the shared cache. Choose per page based on what matters most.
Personalize on the server
When you fetch content or evaluate a query in a route or controller, the package marks the response private automatically, so it is never stored in a shared cache. The visitor still gets the page quickly from your application, and every request is personalized.
This is the default and requires no extra work. Keep your other pages cacheable by not reading visitor data on them.
Personalize on the client
To keep a page in the shared cache, render it without server-side personalization, so the HTML is the same for everyone, then personalize it in the browser.
For example, render a default hero on the server and replace it on the client once the SDK loads:
@extends('layouts.app')
@section('content') <section id="hero"> <h1>Welcome to Croct!</h1> </section>
@croct const heading = document.querySelector('#hero h1');
croct.fetchContent('home-hero').then(({content}) => { heading.textContent = content.title; }); @endcroct@endsectionBecause the page does not depend on the visitor on the server, it stays cacheable. The trade-off is a brief moment where the default content shows before the personalized content loads.