Caching Strategy untuk Aplikasi Laravel
Setiap kali aplikasi Laravel mulai terasa lambat, refleks pertama kebanyakan developer adalah "tinggal di-cache saja". Masalahnya, cache itu bukan satu jenis solusi — ada beberapa lapisan yang bisa dipakai, dan salah pilih lapisan justru bikin aplikasi susah di-debug karena data yang tampil ke user ternyata sudah tidak sinkron dengan database. Saya sering menemui ini di sistem yang datanya berubah cepat, seperti aplikasi klinik atau rumah sakit — kalau cache-nya salah strategi, risiko terburuknya bukan cuma tampilan usang, tapi keputusan yang diambil dari data basi. Jadi sebelum menulis Cache::remember() di mana-mana, penting untuk paham tiga level cache yang tersedia dan kapan masing-masing cocok dipakai.
Tiga level cache: query, halaman, dan computed value
Cache query adalah yang paling umum dan paling aman untuk pemula. Targetnya adalah hasil query database yang mahal tapi jarang berubah, misalnya daftar kategori atau konfigurasi sistem.
$categories = Cache::remember('categories.all', now()->addHours(6), function () {
return Category::orderBy('name')->get();
});Cache jenis ini granular, sehingga invalidasinya juga bisa granular — kita tahu persis key mana yang perlu dihapus saat data berubah.
Cache halaman (page cache) menyimpan hasil render HTML penuh, biasanya lewat middleware atau reverse proxy seperti Varnish/Nginx cache. Ini paling efektif untuk halaman publik yang isinya sama untuk semua pengunjung, misalnya landing page atau artikel blog. Untuk halaman yang isinya bergantung pada user login atau state session, page cache biasanya bukan pilihan yang tepat kecuali kita pecah cache-nya per konteks, yang justru menambah kompleksitas.
Cache computed value menyasar hasil perhitungan yang berat secara CPU, bukan I/O database — misalnya agregasi statistik, hasil pemanggilan API eksternal, atau output dari model AI/LLM yang mahal dipanggil berulang. Bedanya dengan cache query: yang di-cache bukan hasil mentah dari database, tapi hasil akhir setelah diproses.
Aturan praktis yang saya pakai: makin dekat data ke "kebenaran real-time yang penting", makin granular level cache-nya harus. Data konfigurasi boleh di-cache lama dan kasar. Data transaksional atau status yang dibaca banyak orang sebaiknya di-cache di level query dengan TTL pendek, bukan di level halaman.
Strategi invalidasi yang tidak bikin data basi
Bagian tersulit dari caching bukan menyimpan, tapi tahu kapan harus menghapus. Ada dua pendekatan utama yang saya kombinasikan tergantung kebutuhan.
- TTL (time-to-live) pendek — cocok untuk data yang toleran terhadap keterlambatan beberapa menit, misalnya statistik dashboard. Simpel, tidak butuh logika tambahan, tapi selalu ada jendela waktu di mana data bisa basi.
- Invalidasi eksplisit lewat event — begitu ada perubahan data, kita hapus cache key yang relevan lewat model event atau observer. Ini lebih akurat tapi butuh disiplin: setiap tempat yang mengubah data harus "ingat" untuk menghapus cache terkait.
class Category extends Model
{
protected static function booted()
{
static::saved(fn () => Cache::forget('categories.all'));
static::deleted(fn () => Cache::forget('categories.all'));
}
}Untuk sistem yang punya banyak variasi cache key dari data yang sama, pakai cache tags (tersedia di driver seperti Redis) supaya bisa menghapus sekelompok key sekaligus tanpa harus hafal satu per satu. Sebagai ilustrasi, kalau satu entitas punya puluhan variasi key turunan, menghapus manual satu-satu jelas rawan ada yang terlewat — tag menyelesaikan itu dengan satu perintah Cache::tags(['categories'])->flush().
Kapan sebaiknya tidak cache sama sekali
Kadang jawaban terbaik adalah tidak menambah cache. Kalau query sudah cepat karena index yang tepat, atau kalau data berubah hampir di setiap request sehingga cache-nya hampir selalu miss, menambah layer cache cuma menambah kompleksitas tanpa manfaat nyata. Saya selalu cek dulu apakah masalahnya benar-benar performa baca, atau justru query yang belum dioptimalkan, sebelum menutupnya dengan cache.
Takeaway
Pilih level cache sesuai sifat datanya: query cache untuk data yang jarang berubah dan butuh granularitas, page cache untuk konten publik yang seragam, computed cache untuk hasil olahan yang mahal dihitung ulang. Dan yang tidak kalah penting, rancang strategi invalidasinya dari awal — bukan sebagai tambalan setelah user melapor data yang tampil salah.