Laravel’s Hidden Safety Net: What Happens When Cache TTL is Zero

📖 2 minutes read

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.

Daryle De Silva

VP of Technology

11+ years building and scaling web applications. Writing about what I learn in the trenches.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *