Cache::forget

Removes a single item from the cache and reports whether the key was actually there.

Signature
Cache::forget(string $key): bool
  • Added in Laravel 4.0

Parameters

ParameterTypeDescription
$$keystringThe cache key to remove. Only one key per call — there is no array form.

Return value

booltrue when the item was removed, false when the key did not exist or the store failed to delete it.

Errors

Nothing for a missing key; the underlying store may throw a connection exception.

Cache::forget deletes one key. It returns true only if something was actually removed, so a false means the key was already gone — which is normally fine and occasionally a clue that you are forgetting the wrong key.

When to reach for it

Anywhere the source of truth changes and a cached derivative is now wrong: a model observer, the end of an import command, a webhook handler. Pair it with the write. Every forever and every long TTL should have a forget somewhere naming the same key, ideally produced by a shared helper so the two cannot drift.

Cache::pull($key) is read-and-delete in one atomic-ish step, which is what you want for one-shot values like a flash token.

What trips people up

The key must match exactly, prefix included. If you write with Cache::store('redis') and forget on the default store, or a queue worker runs with a different CACHE_PREFIX, nothing is removed and nothing complains.

There is no array form and no wildcard. Cache::forget('user:*') deletes a key literally named user:*. To drop a group of keys use cache tags (Cache::tags(['users'])->flush(), unsupported on the file, database and DynamoDB drivers) or put a version number in the key and bump it.

A tagged item cannot be forgotten without its tags.

Example

Example · php
<?php

use Illuminate\Support\Facades\Cache;

Cache::put('user:7:profile', ['name' => 'Ada'], 3600);

// true: something was there and it is gone now.
var_dump(Cache::forget('user:7:profile'));

// false: the key was already absent. Not an error.
var_dump(Cache::forget('user:7:profile'));

// No wildcards. This removes a key literally named 'user:*'.
var_dump(Cache::forget('user:*'));

// Forget on the same store you wrote to, or nothing happens.
Cache::store('redis')->put('queue:depth', 12, 60);
var_dump(Cache::store('redis')->forget('queue:depth'));

// Read-and-delete in one call.
Cache::put('signup:token', 'abc123', 600);
echo Cache::pull('signup:token'), PHP_EOL;

When to use it

  • Invalidate a cached profile from a model observer when the user record is saved.
  • Drop a stale aggregate at the end of a nightly import so the next request recomputes it.
  • Clear a rate-limit counter after an administrator manually unblocks an account.

Frequently asked questions

Why does Cache::forget return false?

Because the key was not in the store when you asked for it removed. The usual causes are a mismatched key string, forgetting on a different store than the one written to, or a different CACHE_PREFIX in the process doing the forgetting — a queue worker that has not been restarted since the config changed is the classic case.

How do I forget multiple cache keys at once?

forget takes a single key, so loop over the keys, use Cache::tags([...])->flush() on Redis or Memcached, or embed a version number in the key and increment it. Cache::flush() removes everything on the store and ignores the cache prefix, so avoid it on a store shared with other applications.

Does Cache::forget work on tagged items?

Only if you go through the same tags: Cache::tags(['reports'])->forget('revenue'). The tags become part of the underlying key, so an untagged forget with the same name does not find the entry.

More examples

Keeping the key in one place so writes and forgets cannot drift

The bug this avoids is a key string typed twice, once as "user:{$id}:profile" and once as "users:{$id}:profile", which produces a cache that never invalidates and a forget that always returns false. One method owns the key format; the write path and both invalidation hooks call it.

Example · php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Cache;

class User extends Model
{
    public static function profileCacheKey(int $id): string
    {
        return "user:{$id}:profile";
    }

    public static function cachedProfile(int $id): array
    {
        return Cache::remember(static::profileCacheKey($id), 3600, function () use ($id) {
            return static::findOrFail($id)->only(['name', 'email', 'avatar_url']);
        });
    }

    protected static function booted(): void
    {
        static::saved(fn (User $user) => Cache::forget(static::profileCacheKey($user->id)));
        static::deleted(fn (User $user) => Cache::forget(static::profileCacheKey($user->id)));
    }
}

echo User::profileCacheKey(7), PHP_EOL;   // user:7:profile

Dropping a whole group of keys without wildcards

Neither approach uses forget on individual keys, because listing them is exactly what you cannot do. Tags cost a set membership write per entry and are unavailable on the file and database drivers. The version-prefix trick works everywhere and is O(1) to invalidate; the cost is that superseded entries linger until their own TTL expires.

Example · php
<?php

use Illuminate\Support\Facades\Cache;

// Option 1: tags. Redis and Memcached only - not file, database or DynamoDB.
Cache::tags(['reports', 'team:3'])->put('revenue', 1200, 600);
Cache::tags(['reports', 'team:3'])->put('signups', 45, 600);

Cache::tags(['team:3'])->flush();          // both keys above are gone

var_dump(Cache::tags(['reports', 'team:3'])->get('revenue'));   // NULL

// Option 2: a version in the key. Works on every driver.
$version = Cache::get('reports:version', 1);

Cache::put("reports:v{$version}:revenue", 1200, 600);

// "Invalidate everything" becomes a single increment.
Cache::increment('reports:version');

echo Cache::get('reports:version'), PHP_EOL;   // 2

Discussion

  • Be the first to comment on this lesson.