Glossary

Cache

A cache returns a prepared result instead of repeating a database query or remote-service call. Its key, validity, and invalidation must match the data.

Short definition

A temporary copy for faster, less expensive repeated reads.

A cache holds a value that the application has already retrieved or computed. The next request can receive a response from memory, a local file, a reverse proxy, or a specialised data store before the application opens a database connection or calls an external API. A successful use is called a cache hit; if the key is missing or the value has expired, a cache miss occurs and the application must retrieve the value again.

A cache is not a second authoritative database. An order, price, permission, or inventory state has its source of truth, usually a relational database or another owning system. The cache only speeds up reads of a safely defined view. Once the source changes, the application must account for the cache potentially returning an older version for a while and decide where such a delay is acceptable.

What it is used for

Speeding up repeated work, not hiding a poor query

Caching makes sense for data that is read much more often than it changes, or whose computation or retrieval costs measurable time and resources.

  • a product catalogue, category tree, or store settings that change less often than they are read
  • the result of an expensive aggregate query for an administration interface or inventory overview
  • an external-service response with a clear useful lifetime, such as a list of pickup points
  • an HTTP response for public, identical content that does not depend on the signed-in user
  • short-lived technical data, such as feature-flag configuration or a request count for rate limiting

Practical example

A product catalogue by store, language, and currency

An online store displays the same product repeatedly, but the result differs by store, language, and currency. The cache key therefore includes those values. On a miss, the application loads the product from the database, creates a public read model, and stores it with a short TTL. A subsequent name or price change deletes every relevant variant so the next read cannot retrieve the old view.

The code does not use the cache to decide whether an order can be paid or shipped. Those operations work directly with the current database state. Here, the cache is only an optimisation for public product reads.

$key = sprintf('product:v3:%s:%s:%s', $store, $locale, $currency);

$product = $cache->get($key, function () use ($productId, $store, $locale, $currency): ProductView {
    $view = $productViewRepository->find($productId, $store, $locale, $currency);

    return $view ?? throw new ProductNotFound($productId);
}, ttl: 300);

How it works

Cache-aside: the application decides when to read and store a value

The common cache-aside pattern keeps the source of truth outside the cache. The application first looks for a prepared value and creates it from the source on a miss.

  1. Building the key The key describes the exact data view: format version, store, language, currency, and filter. Two different results must not share the same key.
  2. Reading from the cache On a hit, the application verifies that the value still exists and has the expected format. It then returns it without further work against the source.
  3. Miss and source read When the value is missing, the application loads authoritative data or performs the computation. The correctness of the result must not depend on the cache being available.
  4. Storing with a validity policy The result is stored with a TTL, tag, or version. This decision determines how long the value may be used without another check.
  5. Change and invalidation When a product, price, or configuration changes, the relevant key is deleted or its version changed. The next read then safely recomputes the value.

Important concepts

The key, validity, and data owner determine correct cache behaviour.

Choosing Redis, a file cache, CDN, or HTTP cache comes second. First determine which data may safely be stale.

Cache hit, miss, and hit rate

A hit uses an existing value; a miss requires creating it. Hit rate helps evaluate the benefit, but without latency and source impact it does not show whether the cache solves a real problem.

TTL and expiration

Time to live limits the maximum age of a value. A short TTL reduces staleness risk but increases misses; a long TTL saves work at the source but increases the need for active invalidation.

Cache layers

A browser, CDN, nginx, PHP process, and Redis can cache different things. Each layer has its own key, sharing rules, and way of invalidating stale data.

Cache stampede

When a popular key expires, many requests can start the same expensive computation at once. A lock, single-flight mechanism, early refresh, or randomised TTL can help.

Source of truth and fallback

During a cache outage, the application must know whether to read the source safely, return a limited result, or reject the request. A cache should not be the only place where critical state exists.

Benefits and limitations

A faster response in exchange for more state and decisions.

Benefits

  • lower latency and fewer expensive queries or external calls
  • protecting the database and integration service from repeated identical reads
  • the ability to deliver public content closer to the client through the HTTP layer
  • separating an expensive read model from a critical transactional change

Risks and mistakes

  • a stale price, availability, or permission returned from an unsuitable key
  • a cache key without the language, tenant, or user variant mixes different results
  • simultaneous expiration of many keys overloads the source
  • a cache without metrics and limits merely moves the problem to another service
  • premature caching hides a missing index or inefficient database query

Scope of use

Cache measurably expensive reads that are safe to share.

Before introducing a cache, measure the repeated read and fix the underlying issue: a missing database index, an N+1 query, an oversized payload, or an unnecessary external call. A cache addresses a stable read pattern, not every slow response.

It is unsuitable as the only safeguard for state that must be exact on every request, such as payment confirmation, reservation of the last item, or server-side authorization. It can still accelerate supporting data, but the final decision must verify authoritative data and transactional rules.

What to keep in mind

Define, measure, and regularly verify how long values remain valid.

Every cache item needs a key, lifetime, and an owner responsible for invalidation.

  • include every input that can change the result in the key: tenant, language, currency, filter, and format version
  • choose TTL from the actual acceptable staleness, not an arbitrarily high number
  • measure hit rate, value creation time, eviction counts, and impact on the data source
  • design stampede protection for expensive, frequently read keys
  • test behaviour on a miss, expiration, invalidation, and unavailable cache backend
  • do not store sensitive personalised content in a shared cache without clear key separation and access control

Common questions

What a cache speeds up and what it should not decide

Is Redis always a cache?

No. Redis can be used for caching, queues, counters, locks, and other short-lived state. A value’s relationship to the source of truth and whether it can be recreated safely determine whether it is a cache.

Is setting a TTL enough?

TTL limits the age of a value but does not say what happens after a price, permission, or configuration changes. More sensitive data needs active invalidation, key versioning, or another consistency rule.

Should every database query go through a cache?

No. First assess frequency, query cost, suitable indexes, and acceptable staleness. Caching rarely read or constantly changing data can add more complexity than value.

What if the cache goes down?

The application should have a defined fallback: read the source safely, return a limited result, or reject the request. Critical data must not exist only in the cache.

How I work with data in practice

I address performance together with data freshness and outage behaviour.

For online stores, APIs, and integration services, I design caching alongside databases, queues, and operational limits so an optimisation does not change the meaning of a business operation.

Request a call

I will call you on the next working day between 9:00 and 17:00.

You can also call me directly.

+420 605 181 728

Leave your phone number and send a callback request.

By sending, you agree to processing your data in order to handle your request.