Laravel 13 arrived on March 17, 2026, raising the PHP floor to 8.3 and shipping what the team calls “the most developer-experience-forward release since Laravel 5.5”. The three flagship features — PHP Attributes on models, a first-party AI SDK, and native vector search — are fully opt-in and backward-compatible. Upgrading from Laravel 12 is described as the smoothest major version bump in the framework's history.
>PHP 8.3 minimum
⚠ BREAKINGPHP 8.2 is no longer supported. Update your server and CI pipeline to PHP 8.3 before upgrading to Laravel 13.
# Verify before upgrading
php --version # must be >= 8.3
# composer.json
"require": {
"php": "^8.3",
"laravel/framework": "^13.0"
}>PHP Attributes — declarative model configuration
Laravel 13 introduces first-party PHP 8 Attributes as an alternative to array-based model properties. They are entirely opt-in — existing code keeps working unchanged.
<?php
use IlluminateDatabaseEloquentAttributes{
Table, Fillable, Hidden, Cast, ObservedBy, ScopedBy
};
#[Table('users', key: 'user_id', keyType: 'string', incrementing: false)]
#[Fillable(['name', 'email', 'avatar'])]
#[Hidden(['password', 'remember_token'])]
#[Cast('preferences', 'array')]
#[Cast('email_verified_at', 'datetime')]
#[ObservedBy([UserObserver::class])]
class User extends Model
{
// No more $table, $fillable, $hidden, $casts arrays
}
// Attributes also work on Jobs, Commands, Listeners, Mailables
use IlluminateQueueAttributes{Queue, Connection, WithoutOverlapping};
#[Queue('payments')]
#[Connection('redis')]
#[WithoutOverlapping(expiresAt: 300, releaseOnSignal: true)]
class ProcessPayment implements ShouldQueue
{
public function handle(): void { /* ... */ }
}>Laravel AI SDK (first-party)
laravel/ai is a stable first-party package shipping with Laravel 13 starter kits. It provides a unified fluent API over OpenAI and Anthropic, covering text generation, tool-calling agents, embeddings, audio transcription, image generation and vector stores.
composer require laravel/ai<?php
use LaravelAIFacadesAI;
// Text generation
$response = AI::text('Summarise this invoice: ' . $invoice->text);
// Streaming
AI::text('Write a product description for: ' . $product->name)
->stream(fn (string $chunk) => print($chunk));
// Tool-calling agent
$result = AI::agent()
->tools([new SearchInventoryTool, new PriceCalculatorTool])
->run('What is the total price for 3 units of SKU-42?');
// Embeddings → pgvector
$vector = AI::embed('Best wineries in Napa Valley');
$docs = Document::whereVectorSimilarTo('embedding', $vector)->limit(5)->get();
// Switch provider per call
AI::using('anthropic')->text('Classify this support ticket: ' . $ticket->body);NOTEProvider credentials live in .env: OPENAI_API_KEY and ANTHROPIC_API_KEY. The default provider is configured in config/ai.php.
>Native pgvector — semantic search
Laravel 13 ships first-party pgvector support via the query builder and Eloquent, no external packages required.
# Migration
php artisan make:migration add_embedding_to_documents_table<?php
// Migration
Schema::table('documents', function (Blueprint $table) {
$table->vector('embedding', dimensions: 1536); // OpenAI ada-002
});
// Model cast
class Document extends Model
{
#[Cast('embedding', 'vector')]
// or via array: protected $casts = ['embedding' => 'vector'];
}
// Storing an embedding
$doc->embedding = AI::embed($doc->content);
$doc->save();
// Semantic search — cosine similarity (default)
$results = Document::whereVectorSimilarTo('embedding', 'climate change solutions')
->limit(10)
->get();
// Euclidean distance
$results = Document::whereVectorSimilarTo(
'embedding',
'climate change solutions',
distance: 'euclidean',
)->get();>Cache::touch()
Extends a cache entry's TTL without fetching or re-storing the value — a single atomic database operation.
// Before — two round-trips
$value = Cache::get('report:123');
Cache::put('report:123', $value, now()->addHours(2));
// Laravel 13 — one round-trip, value unchanged
Cache::touch('report:123', now()->addHours(2));>Centralised Queue routing
<?php
// AppServiceProvider::boot()
use IlluminateSupportFacadesQueue;
Queue::route(ProcessPayment::class, connection: 'redis', queue: 'payments');
Queue::route(SendInvoice::class, connection: 'database', queue: 'mail');
Queue::route(GenerateReport::class, connection: 'sqs', queue: 'reports');
// Overrides #[Queue] and #[Connection] attributes
// One place for all routing decisions>Upgrade from Laravel 12
# 1. Update PHP to 8.3+
# 2. Update composer.json
composer require laravel/framework:^13.0 --no-update
# 3. Run
composer update
# Laravel Shift for automated migration
# https://laravelshift.com/laravel-12-to-13-upgrade-guide
php artisan about # confirms version 13.x
php artisan config:clear
php artisan cache:clearNOTEThe upgrade guide lists zero code-breaking changes in application code for the 12→13 path. All new APIs are additive and opt-in.