Home Paket Belajar Bootcamp Instruktur

Upgrade Laravel Versi 13

  • author-image

    Kurnia Andi Nugroho

  • Cara upgrade laravel Tutorial upgrade laravel 13 Belajar laravel 13 Update laravel 13
  • blog-comment 0 comment
  • dilihat 12 kali
  • 02 Jun, 2026
blog-thumbnail

Tutorial Lengkap: Upgrade Laravel ke Versi 13

Estimasi Waktu: ~10 Menit Dari versi: Laravel 12.x Ke versi: Laravel 13.x


Pendahuluan

Panduan ini merupakan terjemahan dan pengembangan dari dokumentasi resmi upgrade Laravel 13. Setiap perubahan dikategorikan berdasarkan tingkat dampak:

Tingkat DampakKeterangan
🔴 TinggiKemungkinan besar mempengaruhi aplikasi Anda
🟡 SedangMungkin mempengaruhi sebagian aplikasi
🟢 RendahHanya mempengaruhi fitur/kasus tertentu
Sangat RendahJarang terjadi, biasanya pada implementasi kustom

Tips: Anda bisa menggunakan Shift untuk mengotomatiskan sebagian besar proses upgrade ini, atau gunakan Laravel Boost (MCP server resmi) dengan perintah /upgrade-laravel-v13 di Claude Code, Cursor, atau editor lain yang mendukung MCP.


Persiapan Sebelum Upgrade

Sebelum memulai upgrade, lakukan langkah-langkah berikut:

# 1. Buat backup aplikasi Anda
git add .
git commit -m "chore: backup sebelum upgrade ke Laravel 13"

# 2. Pastikan semua test berjalan (opsional tapi disarankan)
php artisan test

# 3. Periksa versi PHP Anda (Laravel 13 membutuhkan PHP 8.2+)
php -v

Langkah 1 – Update Dependensi (Dampak Tinggi)

🔴 Dampak: Tinggi — Langkah ini wajib dilakukan.

Buka file composer.json di root proyek Anda dan ubah versi paket berikut:

{
    "require": {
        "laravel/framework": "^13.0",
        "laravel/tinker": "^3.0"
    },
    "require-dev": {
        "laravel/boost": "^2.0",
        "phpunit/phpunit": "^12.0",
        "pestphp/pest": "^4.0"
    }
}

Setelah mengubah composer.json, jalankan perintah berikut untuk menginstall dependensi baru:

composer update

Catatan: Jika terjadi konflik dependensi, jalankan composer update --with-all-dependencies.


Langkah 2 – Update Laravel Installer

Jika Anda menggunakan Laravel Installer CLI untuk membuat proyek baru, update installer agar kompatibel dengan Laravel 13:

Jika diinstall via Composer global:

composer global update laravel/installer

Jika menggunakan Laravel Herd: Update aplikasi Herd ke versi terbaru melalui tampilan antarmukanya.


Langkah 3 – Perlindungan CSRF / Request Forgery (Dampak Tinggi)

🔴 Dampak: Tinggi — Perubahan nama middleware dan perilaku baru.

Apa yang berubah?

Middleware CSRF di Laravel 13 telah diganti namanya dari VerifyCsrfToken menjadi PreventRequestForgery. Selain itu, middleware ini sekarang menyertakan verifikasi asal permintaan menggunakan header Sec-Fetch-Site.

VerifyCsrfToken dan ValidateCsrfToken masih tersedia sebagai alias yang sudah deprecated, namun sebaiknya segera diperbarui.

Yang perlu diubah

Cari semua referensi ke VerifyCsrfToken di proyek Anda dan ganti dengan PreventRequestForgery.

Contoh perubahan di test atau route:

use Illuminate\Foundation\Http\Middleware\PreventRequestForgery;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;

// Laravel <= 12.x (lama)
->withoutMiddleware([VerifyCsrfToken::class]);

// Laravel >= 13.x (baru)
->withoutMiddleware([PreventRequestForgery::class]);

Cara mencari referensi lama secara cepat:

grep -r "VerifyCsrfToken" app/ bootstrap/ routes/ tests/

Langkah 4 – Konfigurasi Cache

4a. Prefix Cache dan Nama Cookie Sesi (Dampak Rendah)

🟢 Dampak: Rendah — Hanya mempengaruhi aplikasi yang mengandalkan nilai default framework.

Di Laravel 13, prefix cache dan Redis default kini menggunakan tanda hubung (-) sebagai pemisah, bukan underscore (_).

// Laravel <= 12.x
Str::slug(env('APP_NAME', 'laravel'), '_').'_cache_';

// Laravel >= 13.x
Str::slug(env('APP_NAME', 'laravel')).'-cache-';

Solusi: Jika aplikasi Anda bergantung pada nilai default ini, tambahkan konfigurasi eksplisit di file .env:

CACHE_PREFIX=nama_aplikasi_cache_
REDIS_PREFIX=nama_aplikasi_
SESSION_COOKIE=nama_aplikasi_session

4b. Konfigurasi serializable_classes (Dampak Sedang)

🟡 Dampak: Sedang — Perubahan keamanan penting.

Laravel 13 menambahkan opsi serializable_classes di konfigurasi cache dengan nilai default false. Ini meningkatkan keamanan dari serangan PHP deserialization gadget chain jika APP_KEY bocor.

Buka file config/cache.php. Jika opsi ini belum ada, tambahkan:

'serializable_classes' => false,

Jika aplikasi Anda menyimpan objek PHP di cache, Anda perlu mendaftarkan class yang diizinkan secara eksplisit:

'serializable_classes' => [
    App\Data\CachedDashboardStats::class,
    App\Support\CachedPricingSnapshot::class,
],

Peringatan: Jika sebelumnya Anda menyimpan objek PHP sembarang di cache tanpa daftar class eksplisit, Anda perlu memigrasikan data tersebut ke format non-objek (misalnya array) atau mendaftarkan class-nya secara eksplisit.


Langkah 5 – Database

5a. upsert dengan MySQL atau MariaDB (Dampak Sedang)

🟡 Dampak: Sedang

Laravel 13 kini memvalidasi bahwa argumen uniqueBy pada method upsert tidak boleh kosong. Jika kosong, akan melempar InvalidArgumentException.

// Pastikan uniqueBy selalu diisi
DB::table('users')->upsert(
    [['email' => '[email protected]', 'name' => 'Test']],
    ['email'],        // <-- uniqueBy, tidak boleh kosong
    ['name']
);

Periksa semua penggunaan upsert di proyek Anda:

grep -r "upsert" app/ database/

5b. Query DELETE dengan JOIN, ORDER BY, dan LIMIT di MySQL (Dampak Rendah)

🟢 Dampak: Rendah

Laravel 13 sekarang mengikutsertakan klausa ORDER BY dan LIMIT pada query DELETE ... JOIN untuk MySQL. Sebelumnya, klausa ini bisa diabaikan secara diam-diam.

Jika mesin database Anda tidak mendukung sintaks ini, mungkin akan muncul QueryException. Periksa query DELETE yang menggunakan JOIN di aplikasi Anda.


Langkah 6 – Container

Container::call dan Nullable Class Defaults (Dampak Rendah)

🟢 Dampak: Rendah

Container::call kini menghormati nilai default nullable untuk parameter class saat tidak ada binding yang ditemukan.

$container->call(function (?Carbon $date = null) {
    return $date;
});

// Laravel <= 12.x: mengembalikan instance Carbon
// Laravel >= 13.x: mengembalikan null

Jika logika injeksi method Anda bergantung pada perilaku lama (selalu mendapat instance meski nullable), perbarui kode tersebut.


Langkah 7 – Queue (Antrian)

7a. Perubahan pada Event JobAttempted (Dampak Rendah)

🟢 Dampak: Rendah

Property pada event Illuminate\Queue\Events\JobAttempted berubah:

// Laravel <= 12.x (lama)
$event->exceptionOccurred; // boolean

// Laravel >= 13.x (baru)
$event->exception; // objek Exception atau null

Cara mencari listener yang terpengaruh:

grep -r "JobAttempted\|exceptionOccurred" app/Listeners/ app/Providers/

Perbarui listener Anda:

// Sebelum
if ($event->exceptionOccurred) { ... }

// Sesudah
if ($event->exception !== null) { ... }

7b. Rename Property Event QueueBusy (Dampak Rendah)

🟢 Dampak: Rendah

Property $connection pada event Illuminate\Queue\Events\QueueBusy diganti menjadi $connectionName:

// Laravel <= 12.x
$event->connection;

// Laravel >= 13.x
$event->connectionName;

Langkah 8 – Routing

Prioritas Registrasi Domain Route (Dampak Rendah)

🟢 Dampak: Rendah

Route dengan domain eksplisit kini diprioritaskan sebelum route tanpa domain dalam pencocokan route. Ini membuat catch-all subdomain route bekerja lebih konsisten.

Jika aplikasi Anda memiliki kombinasi domain dan non-domain route, uji kembali perilaku pencocokan route Anda:

php artisan route:list

Langkah 9 – Eloquent & Collection

9a. Model Booting dan Nested Instantiation (Dampak Sangat Rendah)

Dampak: Sangat Rendah

Membuat instance model baru saat model tersebut masih dalam proses booting sekarang akan melempar LogicException.

// Tidak lagi diizinkan
protected static function boot()
{
    parent::boot();
    (new static())->getTable(); // ❌ Akan melempar LogicException
}

Pindahkan logika seperti ini ke luar siklus boot.

9b. Nama Tabel Polymorphic Pivot (Dampak Rendah)

🟢 Dampak: Rendah

Nama tabel yang digenerate otomatis untuk polymorphic pivot model kustom kini menggunakan bentuk jamak (plural). Jika Anda bergantung pada nama singular sebelumnya, tambahkan definisi tabel eksplisit di pivot model Anda:

class RoleUser extends MorphPivot
{
    protected $table = 'role_user'; // definisikan eksplisit
}

9c. Serialisasi Collection Model Mengembalikan Relasi Eager-Loaded (Dampak Rendah)

🟢 Dampak: Rendah

Saat collection model Eloquent diserialisasi dan dipulihkan (misalnya dalam queued job), relasi yang di-eager-load kini juga dipulihkan. Jika kode Anda mengasumsikan relasi tidak ada setelah deserialisasi, sesuaikan logika tersebut.


Langkah 10 – Perubahan Lainnya

Support: Manager extend Callback Binding (Dampak Rendah)

🟢 Dampak: Rendah

Closure yang didaftarkan via manager extend sekarang di-bind ke instance manager. Jika sebelumnya Anda menggunakan $this di dalam closure untuk merujuk ke service provider, gunakan use untuk menangkap nilainya:

// Sebelum (mungkin tidak bekerja seperti yang diharapkan)
$manager->extend('driver', function () {
    return $this->someMethod(); // $this dulu = service provider
});

// Sesudah (gunakan use)
$manager->extend('driver', function () use ($serviceProvider) {
    return $serviceProvider->someMethod();
});

Support: Str Factories Direset Antar Test (Dampak Rendah)

🟢 Dampak: Rendah

Custom factory untuk UUID, ULID, dan random string kini direset setelah setiap test. Jika test Anda bergantung pada factory yang persisten antar method test, pindahkan setup ke setUp() atau di dalam setiap test:

protected function setUp(): void
{
    parent::setUp();
    Str::createUuidsUsing(fn () => '...');
}

Views: Nama View Paginasi Bootstrap (Dampak Rendah)

🟢 Dampak: Rendah

Nama view pagination Bootstrap 3 telah diperbarui:

// Laravel <= 12.x
'pagination::default'
'pagination::simple-default'

// Laravel >= 13.x
'pagination::bootstrap-3'
'pagination::simple-bootstrap-3'

Perbarui referensi langsung ke nama view lama di kode Anda.

Utilities: Konflik Fungsi Global PHP 8.5 Polyfill (Dampak Rendah)

🟢 Dampak: Rendah

Laravel 13 menambahkan dependency symfony/polyfill-php85 yang mendefinisikan fungsi global seperti array_first() dan array_last() pada PHP versi di bawah 8.5. Ini bisa konflik dengan helper lama.

Solusi terbaik: Gunakan metode dari Illuminate\Support\Arr:

use Illuminate\Support\Arr;

// Gunakan ini sebagai pengganti array_first()
Arr::first($array, function ($value) {
    return /* kondisi */;
});

Verifikasi Akhir

Setelah semua perubahan diterapkan, jalankan langkah-langkah berikut untuk memastikan aplikasi berjalan dengan benar:

# 1. Bersihkan cache
php artisan config:clear
php artisan cache:clear
php artisan route:clear
php artisan view:clear

# 2. Jalankan seluruh test suite
php artisan test

# 3. Cek apakah ada warning atau error
php artisan about

# 4. Periksa route list
php artisan route:list

Jika semua test lulus dan aplikasi berjalan normal, upgrade Anda berhasil! 🎉


Ringkasan Perubahan

NoAreaPerubahanDampak
1DependensiUpdate versi di composer.json🔴 Tinggi
2SecurityVerifyCsrfTokenPreventRequestForgery🔴 Tinggi
3Cacheserializable_classes config baru🟡 Sedang
4Databaseupsert wajib isi uniqueBy🟡 Sedang
5CachePrefix berubah dari _ ke -🟢 Rendah
6ContainerContainer::call nullable default🟢 Rendah
7QueueexceptionOccurredexception🟢 Rendah
8Queue$connection$connectionName🟢 Rendah
9RoutingDomain route diprioritaskan🟢 Rendah
10EloquentPolymorphic pivot nama plural🟢 Rendah
11EloquentEager-loaded relations dipulihkan🟢 Rendah
12SupportManager extend binding ke manager🟢 Rendah
13SupportStr factory direset antar test🟢 Rendah
14ViewsNama view pagination Bootstrap 3🟢 Rendah

Panduan ini dibuat berdasarkan dokumentasi resmi Laravel 13 Upgrade Guide. Selalu periksa dokumentasi resmi Laravel untuk informasi terbaru.

author_photo
Kurnia Andi Nugroho

Web & Mobile App Developer, Laravel, Inertia, Vue.Js, React.Js

Founder of Lagikoding.com Laravel Enthusiast & Web Developer