Dashboard admin yang menampilkan omzet bulan ini, produk terlaris, dan jumlah pelanggan baru biasanya menjalankan query agregat yang sama setiap kali halaman dibuka. Dengan sepuluh staf yang membuka dashboard berulang kali, database mengerjakan perhitungan identik ratusan kali per jam. Halaman jadi lambat, padahal datanya hampir tidak berubah.
Caching menyimpan hasil perhitungan itu sekali lalu menyajikannya kembali tanpa menyentuh database. Panduan ini membahas caching di Laravel 11: memilih driver, pola remember(), strategi invalidasi yang tidak membuat data basi, cache stampede, serta cache bawaan framework untuk deploy.
1. Ukur Dulu, Baru Cache
Cache bukan obat untuk semua kelambatan. Sebelum menambahkannya, pastikan di mana waktunya habis:
- Pasang Laravel Debugbar (development) atau Laravel Telescope untuk melihat jumlah dan durasi query per halaman.
- Jika jumlah query puluhan atau ratusan, kemungkinan besar masalahnya N+1. Perbaiki dengan eager loading dulu.
- Jika query sedikit tetapi masing-masing lambat, cek index di kolom yang difilter.
- Baru setelah itu, cache hasil yang memang mahal dan jarang berubah.
Cache yang menutupi query buruk hanya menunda masalah: ketika cache kedaluwarsa, pengguna pertama tetap menunggu lama.
2. Memilih Driver Cache
Driver diatur lewat CACHE_STORE di .env. Proyek Laravel 11 baru memakai database secara default.
| Driver | Kelebihan | Kekurangan | Cocok untuk |
|---|---|---|---|
| file | Tanpa layanan tambahan | Lambat jika file banyak, tidak bisa dibagi antar server | Shared hosting, aplikasi kecil |
| database | Mudah, sudah ada tabel cache | Menambah beban ke database yang ingin Anda ringankan | Awal proyek, trafik rendah |
| redis | Sangat cepat, mendukung tags dan lock atomik | Butuh server Redis | VPS, trafik menengah sampai tinggi |
| memcached | Cepat, ringan | Fitur lebih sedikit dari Redis | Infrastruktur yang sudah memakainya |
| array | Hanya hidup selama satu request | Tidak persisten | Testing |
Karena kode aplikasi memakai facade Cache yang sama, Anda bisa mulai dengan file di shared hosting lalu pindah ke redis di VPS tanpa mengubah kode.
3. Pola Cache::remember
Pola paling berguna: ambil dari cache jika ada; jika tidak, jalankan closure, simpan hasilnya, lalu kembalikan.
use Illuminate\Support\Facades\Cache;
$stats = Cache::remember('dashboard:stats:' . now()->format('Y-m'), now()->addMinutes(10), function () {
return [
'omzet' => Order::where('status', 'paid')
->whereMonth('created_at', now()->month)
->whereYear('created_at', now()->year)
->sum('total'),
'pesanan' => Order::whereDate('created_at', today())->count(),
'pelanggan' => Customer::whereMonth('created_at', now()->month)->count(),
];
});
Beberapa hal penting dari contoh di atas:
- Kunci mengandung periode (
2026-10), sehingga bulan baru otomatis memakai kunci baru. - TTL pendek (10 menit) karena angka dashboard boleh sedikit tertinggal, tetapi jangan sampai berjam-jam.
- Simpan array atau nilai sederhana, bukan objek besar, agar ukuran cache kecil.
Method lain yang sering dipakai: Cache::get(), Cache::put(), Cache::forget(), Cache::rememberForever(), dan Cache::increment() untuk penghitung.
4. Invalidasi: Bagian yang Paling Sulit
Data basi lebih berbahaya daripada halaman lambat. Bayangkan harga produk sudah diubah, tetapi katalog masih menampilkan harga lama selama satu jam. Ada tiga strategi:
- TTL saja: cache kedaluwarsa sendiri. Cocok untuk statistik yang boleh tertinggal beberapa menit.
- Hapus saat data berubah: panggil
Cache::forget()ketika model disimpan atau dihapus. - Versi di kunci: simpan nomor versi, naikkan saat data berubah, sehingga kunci lama tidak dipakai lagi.
Strategi kedua paling rapi jika ditaruh di event model, bukan disebar di controller:
// app/Models/Product.php
protected static function booted(): void
{
$flush = function () {
Cache::forget('catalog:featured');
Cache::forget('catalog:categories');
};
static::saved($flush);
static::deleted($flush);
}
Jika memakai Redis, cache tags memudahkan menghapus sekelompok kunci sekaligus:
Cache::tags(['catalog'])->remember('catalog:featured', 3600, fn () => Product::featured()->get());
// saat produk berubah
Cache::tags(['catalog'])->flush();
Tags tidak didukung driver file dan database. Memanggilnya di driver tersebut akan menghasilkan error "This cache store does not support tagging".
5. Cache Stampede dan Lock
Misalkan cache laporan berat kedaluwarsa tepat ketika 50 pengguna membuka halaman. Kelimapuluh request melihat cache kosong dan menjalankan query berat bersamaan, sehingga database kewalahan. Ini disebut cache stampede. Dua cara mengatasinya:
// a) Lock atomik: hanya satu proses yang menghitung ulang
$report = Cache::get('report:monthly');
if ($report === null) {
$report = Cache::lock('report:monthly:lock', 30)->block(10, function () {
return Cache::remember('report:monthly', 3600, fn () => ReportService::build());
});
}
// b) Stale-while-revalidate (Laravel 11.23+):
// segar 5 menit, boleh disajikan basi sampai 15 menit sambil dihitung ulang di belakang
$report = Cache::flexible('report:monthly', [300, 900], fn () => ReportService::build());
Lock membutuhkan driver yang mendukung lock atomik seperti redis, memcached, database, atau file.
6. Cache Bawaan Framework untuk Produksi
Selain cache data, Laravel bisa meng-cache konfigurasi, route, view, dan event. Jalankan saat deploy:
php artisan optimize # config, route, view, event sekaligus
php artisan optimize:clear # hapus semuanya saat debugging
Efek samping yang sering mengejutkan: setelah config:cache, fungsi env() yang dipanggil di luar folder config akan mengembalikan null. Selalu baca nilai lewat config('app.xxx'), dan definisikan env() hanya di file konfigurasi.
7. Apa yang Sebaiknya Tidak Di-cache
- Saldo, stok saat checkout, dan status pembayaran. Data ini harus selalu dibaca langsung.
- Data per pengguna dengan kunci yang sama untuk semua orang. Selalu masukkan ID pengguna ke kunci, misalnya
user:42:cart, atau data pelanggan bisa tertukar. - Halaman utuh yang berisi token CSRF atau nama pengguna yang sedang login.
- Objek koneksi atau closure yang tidak bisa diserialisasi.
8. Error Umum dan Solusinya
- Perubahan data tidak muncul: kunci tidak di-
forgetsetelah update. Pindahkan invalidasi ke event model. - "This cache store does not support tagging": memakai tags di driver file atau database. Ganti ke Redis atau hapus tags.
- Folder storage/framework/cache membengkak: banyak kunci dinamis dengan TTL panjang di driver file. Pakai TTL wajar dan jalankan
php artisan cache:clearsecara berkala jika perlu. - Nilai .env tidak terbaca di produksi: efek
config:cache. Pakaiconfig().
Checklist Caching
- Masalah N+1 dan index sudah diperbaiki sebelum menambah cache.
- Setiap kunci punya prefix jelas (
dashboard:,catalog:) dan memuat ID pengguna bila datanya pribadi. - Setiap cache punya TTL atau mekanisme invalidasi yang tertulis.
- Data transaksi dan saldo tidak pernah di-cache.
php artisan optimizeada di skrip deploy.
Cache bekerja paling baik di atas query yang sudah efisien, jadi baca juga optimasi performa query Eloquent. Untuk pekerjaan berat yang bisa dihitung di belakang layar, gabungkan dengan queue dan job Laravel, dan masukkan langkah optimize ke prosedur di panduan deploy Laravel ke hosting.