# Cache

Where an environment keeps its cache, what each store can and cannot do, and why Object Storage is the first choice.


Nothing stays running on a serverless container, and an environment runs more than one of them. Where the cache goes decides whether a value one container worked out is there for the next, and whether it survives a container that goes away. Brewless names a store for every environment, so the framework's own default — a database that your environment need not have — never decides it for you.

## What your environment gets

At its first deploy an environment gets `CACHE_STORE` set to the first of these it has:

| It has | `CACHE_STORE` | Shared between containers | Survives a container |
|---|---|---|---|
| A cache (Managed Redis) | `redis` | Yes | Yes |
| A database | `database` | Yes | Yes |
| A bucket | `storage` | Yes | Yes |
| None of these | `file` | No | No |

Most environments have a bucket and no cache, so for most of them the answer is `storage`: the cache goes in the Object Storage bucket the environment already has, under `framework/cache/data`. The variables get `CACHE_STORAGE_DISK=s3` with it.

`SESSION_DRIVER` follows the same choice, except for `storage` and `file`: a session is read and written on every request, which Object Storage would make two calls of and a container's own disk would lose. Those get `cookie`, which the next container reads as well.

> [!NOTE]
> These are the variables of a new environment. An environment that has variables already keeps every value it has, so a store you chose yourself is never replaced. Change it on the **Variables** tab or with `brewless env:push`.

## Why Object Storage first

A bucket is the only shared, lasting place an environment has without paying for something that runs. Scaleway bills Object Storage for what you store and the requests you make; Managed Redis is billed by the size of its nodes for every hour it exists, awake or not. For a cache that is read a few hundred times an hour, the bucket costs cents and the cache costs tens of euros a month.

It also beats the alternatives an environment without Redis would otherwise fall to:

- **Against the container's own disk** (`file`), which is where the framework would land without a database: what one container cached, another does not have, and a value cached forever is gone the moment that container goes away. A page that caches an expensive query would work it out again in every container, and `Cache::forever()` means "until this container dies". With a bucket, every container of the environment reads the same cache.
- **Against the database**, which is shared and lasting too, but every cache hit is then a query on the database your application also serves pages from — and a serverless database has to wake up for it. If you have a database and a busy cache, `database` is still a reasonable choice; the point is that a bucket does not make you buy one.

What it costs you is latency: a cache hit is a request to Object Storage, so it is milliseconds rather than microseconds. That is a good trade for values that are expensive to work out and read now and then, and a poor one for a value read fifty times in a single request. Cache those in memory for the length of the request (`Cache::driver('array')`), or give the environment a Redis cache.

## What the storage store cannot do

Laravel's storage store writes through a disk, which is an ordinary file store at the other end. Three things follow, and they are the reason it is not the answer for every application:

- **No locks.** It is the only store Laravel ships that is not a `LockProvider`, so `Cache::lock()` raises an exception on it. Laravel's own scheduler notices and falls back, so `withoutOverlapping()` keeps working, but code of yours that takes a lock directly does not.
- **`add()` and `increment()` are not atomic.** Both read and then write, so two containers doing it at the same moment can overwrite one another. A rate limiter or a counter on this store counts low under load.
- **No tags.** `Cache::tags()` needs a taggable store; only `redis`, `memcached` and `array` are. The same is true of `file`, `database` and `dynamodb`, so this is nothing you lose by moving from them.

If your application needs any of these, give the environment a cache (see [A cache](/applications/applications-and-environments#a-cache)) or point `CACHE_STORE` at its database.

## The stores, and when to use which

| Store | Shared | Lasting | Locks | Tags | Use it when |
|---|---|---|---|---|---|
| `storage` | Yes | Yes | No | No | The default without Redis: a shared cache for nothing but a bucket |
| `redis` | Yes | Yes | Yes | Yes | A busy cache, locks, tags, sessions in a store; worth its hourly bill |
| `database` | Yes | Yes | Yes | No | You have a database and the cache is quiet enough to share it |
| `file` | No | No | Per container | No | Nothing else is there, or a container-local scratch |
| `array` | No | No | Per request | Yes | Within one request, and in tests |
| `null` | — | — | — | — | Switching the cache off, usually in tests |
| `octane` | No | No | Per worker | No | Laravel Octane only; it lives in the worker's memory |
| `memcached`, `dynamodb`, `apc` | — | — | — | — | Not offered by Brewless; set them yourself if you run them |

`failover` is not a place to keep things but a list of stores tried in order, which is worth knowing if you want a Redis cache that falls back to the bucket when it is unreachable.

## Checking what an environment uses

```bash
brewless command production "config:show cache.default"
```

The store has to exist in your application's `config/cache.php`. The framework's own stores are merged into yours, so `storage` is there even when your file does not list it; a store of your own making has to be in the file.
