Table of Contents
Laravel’s Hidden Safety Net: What Happens When Cache TTL is Zero
While working on caching implementation for an API client, I discovered an interesting Laravel behavior that isn’t widely documented: what happens when you try to cache data with a TTL of zero or less?
The Discovery
I had code that looked like this:
$ttl = $this->authSession->getRemainingTtl(); // Could be 0 if expired
$this->cache->put($cacheKey, $result, $ttl);
My concern was: what if getRemainingTtl() returns 0 because the auth session expired? Would Laravel:
- Store the data anyway (bad – invalid cache)
- Throw an exception (annoying but safe)
- Silently ignore it (confusing)
- Do something smarter?
The Answer: Laravel Deletes The Key
Diving into vendor/laravel/framework/src/Illuminate/Cache/Repository.php, lines 197-220:
public function put($key, $value, $ttl = null)
{
if (is_array($key)) {
return $this->putMany($key, $value);
}
if ($ttl === null) {
return $this->forever($key, $value);
}
$seconds = $this->getSeconds($ttl);
if ($seconds <= 0) {
return $this->forget($key); // ← The magic line
}
$result = $this->store->put($this->itemKey($key), $value, $seconds);
if ($result) {
$this->event(new KeyWritten($key, $value, $seconds));
}
return $result;
}
When TTL ≤ 0, Laravel calls forget($key) – it actively deletes the cache entry.
Why This Is Brilliant
This behavior prevents a class of bugs:
- If the key doesn’t exist yet → nothing happens (safe, no-op)
- If the key already exists → it gets deleted (removes stale data)
- No invalid cache entries with expired TTL ever get stored
This means you don’t need defensive code like:
// ❌ Unnecessary guard
if ($ttl > 0) {
$this->cache->put($cacheKey, $result, $ttl);
}
You can safely do:
// ✅ Laravel handles it gracefully
$this->cache->put($cacheKey, $result, $this->authSession->getRemainingTtl());
Practical Applications
This is particularly useful when caching API responses with dynamic TTLs tied to auth tokens:
public function fetchData(string $endpoint): array
{
$cacheKey = "api:{$endpoint}";
$cached = $this->cache->get($cacheKey);
if ($cached) {
return $cached;
}
$this->ensureAuthenticated();
$data = $this->request('GET', $endpoint);
// Cache expires when auth token expires
// If token is already expired (TTL = 0), Laravel auto-deletes the key
$this->cache->put(
$cacheKey,
$data,
$this->authToken->getExpiresIn()
);
return $data;
}
The Takeaway
Laravel’s cache implementation has thoughtful edge-case handling. When you pass TTL ≤ 0 to put(), it doesn’t fail or store invalid data – it actively cleans up by deleting the key. This makes caching with dynamic TTLs safer and requires less defensive code.
Small framework details like this add up to more robust applications.
Leave a Reply