# 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](/reference/sdk/php/api/options/fetch-options/with-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.

> **Cache on the edge, personalize per request**
>
> You never have to trade caching for personalization. Cache your pages aggressively, all the way to the edge, and still tailor them per visitor, on the [server](#server) or on the [client](#client).

## 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 \[#server]

When you [fetch content](/reference/sdk/laravel/content-rendering) or [evaluate a query](/reference/sdk/laravel/query-evaluation) 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 \[#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:

**resources/views/home.blade.php**

```blade
@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
@endsection
```

Because 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.

## Explore

- [Content rendering](/reference/sdk/laravel/content-rendering): Learn how to fetch and render content for your slots.
- [Static content](/reference/sdk/php/api/options/fetch-options/with-static-content): Mark a fetch as static so the response stays cacheable.
