Everything New in Laravel 13: The Complete Guide
Blog article/Blog archive

Everything New in Laravel 13: The Complete Guide

Laravel 13 dropped on March 17, 2026, and I've spent the last two days digging through every commit, PR, and doc page. There's a lot to unpack here. This isn't one of those "minor version bump" releas

Mar 23, 202611 min read0 comments68 views
LaravelPHPwebdevAIBeginner Developers

Laravel 13 dropped on March 17, 2026, and I've spent the last two days digging through every commit, PR, and doc page. There's a lot to unpack here. This isn't one of those "minor version bump" releases. The framework took some real swings this time around.

I'm going to walk you through every major feature, the stuff that matters, and the stuff you'll actually use in your day-to-day work. We're talking PHP attributes across the entire framework, a first-party AI SDK, native vector search, passkey auth, and a bunch of smaller quality-of-life improvements that add up fast.

If you want the official changelog, check out the Laravel 13 release notes. But if you want the practical breakdown with real code examples and honest opinions, keep reading.

Let's get into it.

Developer working on laptop with code Photo by Lukas Blazek on Pexels

PHP Attributes Everywhere

This is the biggest developer experience change in Laravel 13, and honestly, it's the one I'm most excited about. The framework now supports PHP attributes in over 15 different locations. All of them are fully optional and backward-compatible. Your existing code keeps working. You just get a cleaner way to do things if you want it.

Let me show you what this looks like in practice. PR #58578 is the main one to follow.

Eloquent models can now use attributes for observers and scopes:

use Illuminate\Database\Eloquent\Attributes\ObservedBy;
use Illuminate\Database\Eloquent\Attributes\ScopedBy;

#[ObservedBy(UserObserver::class)]
#[ScopedBy(ActiveScope::class)]
class HrrUser extends Model
{
    // No more boot() boilerplate
}

Queue jobs get rate limiting and overlap prevention right on the class:

use Illuminate\Queue\Attributes\WithoutOverlapping;
use Illuminate\Queue\Attributes\RateLimited;

#[WithoutOverlapping(key: 'user-{userId}')]
#[RateLimited('default')]
class HrrProcessPaymentJob implements ShouldQueue
{
    public function __construct(public int $userId) {}

    public function handle(): void
    {
        // payment logic
    }
}

Controllers can apply middleware to individual methods instead of the constructor:

use Illuminate\Routing\Attributes\Middleware;

class HrrOrderController extends Controller
{
    #[Middleware(['auth', 'verified'])]
    public function store(Request $request): Response
    {
        // create order
    }
}

And Artisan commands can define their schedule right on the class:

use Illuminate\Console\Attributes\Schedule;

#[Schedule('daily')]
class HrrSendDailyReportCommand extends Command
{
    protected $signature = 'hrr:daily-report';

    public function handle(): void
    {
        // send report
    }
}

So what's actually going away? Nothing. The old $casts array, the boot() method, the Kernel.php scheduling, all of that still works. Attributes are just a cleaner alternative that keeps your configuration closer to the code it affects. No breaking changes.

This is my favorite change in this release. It makes your code more scannable and cuts down on the boilerplate you have to remember.

Clean organized code structure Photo by Bibek ghosh on Pexels

Laravel AI SDK

The laravel/ai package hit stable 1.0 alongside this release, and it's a big deal. Laravel now has first-party support for AI across multiple providers. OpenAI, Anthropic, and Gemini all work out of the box. You get text generation, image generation, audio transcription, embeddings, and even agents with tool support.

The API is clean and fluent, exactly what you'd expect from a Laravel package:

use Laravel\AI\Facades\AI;

// Text generation
\(response = AI::text('Write a product description for ' . \)product->name);

// With a specific provider
\(response = AI::provider('anthropic')->text('Summarize this document: ' . \)doc->content);

// Embeddings for semantic search
$vector = AI::embeddings('Laravel is a PHP framework');

// Agent with tools
$result = AI::agent()
    ->tools([new HrrSearchTool(), new HrrCalculateTool()])
    ->run('Find the best product for under $50 and calculate shipping');

Setting up multiple providers is straightforward in the config:

// config/ai.php
'providers' => [
    'openai' => [
        'driver' => 'openai',
        'api_key' => env('OPENAI_API_KEY'),
        'model' => 'gpt-4o',
    ],
    'anthropic' => [
        'driver' => 'anthropic',
        'api_key' => env('ANTHROPIC_API_KEY'),
        'model' => 'claude-sonnet-4-6',
    ],
],
'default' => env('AI_PROVIDER', 'openai'),

The agents feature is the one that caught my eye. You define tool classes, hand them to the agent, and it figures out when to call them. It's the kind of thing you'd normally need LangChain or a custom orchestrator for. Now it's built into your Laravel app with a one-liner.

Check out the full package at github.com/laravel/ai. I'll be writing a deeper dive on this one soon.

Robot and AI technology Photo by Vladimir Srajber on Pexels

Semantic Search with pgvector

Laravel 13 ships first-class pgvector support, and it pairs perfectly with the AI SDK embeddings from the previous section. If you've ever wanted to build "search by meaning" into your app instead of just keyword matching, this is how you do it now.

Start with a migration. The new vector column type handles everything:

Schema::create('hrr_articles', function (Blueprint $table) {
    $table->id();
    $table->string('title');
    $table->text('content');
    $table->vector('embedding', dimensions: 1536);
    $table->timestamps();
});

Your model uses the new HasVector attribute to declare the vector column:

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Attributes\HasVector;

#[HasVector('embedding', dimensions: 1536)]
class HrrArticle extends Model
{
    protected $fillable = ['title', 'content', 'embedding'];
}

Now querying by similarity is just a few lines:

use Laravel\AI\Facades\AI;

// Get embedding for the search query
\(queryVector = AI::embeddings(\)request->query('q'));

// Find similar articles
\(articles = HrrArticle::whereVectorSimilarTo('embedding', \)queryVector)
    ->orderByVectorDistance('embedding', $queryVector)
    ->limit(10)
    ->get();

Notice how the AI SDK embeddings feed directly into the vector query. Generate the embedding, pass it to the Eloquent query builder, done. No external vector databases. No complicated setup. Just PostgreSQL with the pgvector extension and your normal Laravel app.

You will need PostgreSQL with pgvector installed. If you're on a managed database like AWS RDS or Neon, pgvector is usually available as an extension you can enable. For local development, the official pgvector Docker image works great.

JSON:API Resources and Passkey Authentication

Two distinct features here, but both are things people have been asking for. Let's cover them together.

JSON:API Resources

Laravel 13 adds a JsonApiResource class that produces spec-compliant JSON:API responses. If you've ever had to build a JSON:API backend by hand or pull in a third-party package, you know how tedious that envelope format can be. Now it's built in.

use Illuminate\Http\Resources\Json\JsonApiResource;

class HrrUserResource extends JsonApiResource
{
    public function toAttributes(Request $request): array
    {
        return [
            'name' => $this->name,
            'email' => $this->email,
            'created_at' => $this->created_at,
        ];
    }

    public function toRelationships(Request $request): array
    {
        return [
            'posts' => HrrPostResource::collection($this->posts),
        ];
    }
}

That automatically produces the proper JSON:API envelope with data.type, data.id, data.attributes, and data.relationships. No manual wrapping. No string concatenation for the type field. It just works.

Passkey Authentication (WebAuthn)

Laravel 13 starter kits now include passkey authentication out of the box. Touch ID, Face ID, hardware security keys. No third-party packages. No paid services. It's all built in.

// routes/web.php
Route::post('/passkeys/register', [PasskeyController::class, 'store'])
    ->middleware('auth');

Route::post('/passkeys/authenticate', [PasskeyController::class, 'authenticate']);
use Laravel\Auth\Passkeys\PasskeyRegistration;
use Laravel\Auth\Passkeys\PasskeyAuthentication;

class HrrPasskeyController extends Controller
{
    public function store(Request $request): JsonResponse
    {
        \(passkey = PasskeyRegistration::verify(\)request);
        \(request->user()->passkeys()->save(\)passkey);

        return response()->json(['registered' => true]);
    }
}

I've been waiting for native passkey support in Laravel for a while. The WebAuthn spec is complex and the existing packages required a lot of configuration. This implementation is clean. You add a few routes, call the verify method, and your users can log in with their fingerprint or face. That's it.

Biometric security authentication Photo by cottonbro studio on Pexels

Laravel Boost MCP Server

This one is interesting. Laravel 13 ships laravel/boost, a first-party MCP (Model Context Protocol) server that lets AI agents interact with your Laravel application. It comes with 15 built-in tools for things like running Artisan commands, querying your database, inspecting routes and models, running migrations, and executing tests.

# Install Boost
composer require laravel/boost

# Start the MCP server
php artisan boost:serve

# Or use the CLI directly
./vendor/bin/boost

To connect it to your AI editor (Claude Desktop, Cursor, or anything that supports MCP), just add it to your config:

// .mcp.json (for Claude Desktop, Cursor, etc.)
{
  "mcpServers": {
    "laravel-boost": {
      "command": "./vendor/bin/boost",
      "args": [],
      "cwd": "/path/to/your/app"
    }
  }
}

The 15 built-in tools cover most of what you'd want an AI agent to do with your app. Artisan runner, route inspector, model explorer, migration runner, test runner, log reader, and more. But here's the thing that really stands out. Boost includes a /upgrade-laravel-v13 prompt that walks AI agents through the entire upgrade process automatically. It inspects your codebase, identifies deprecated patterns, and suggests the changes you need.

If you're already using AI-assisted development, this is a natural extension of your workflow. And if you're not, this might be the feature that gets you started.

Check out the full tool list at github.com/laravel/boost.

Everything Else Worth Knowing

There are a handful of smaller changes in Laravel 13 that don't warrant their own section but are still worth knowing about. Let me run through them quickly.

PreventRequestForgery Middleware

You can now explicitly opt in or out of CSRF-like verification on specific routes:

use Illuminate\Foundation\Http\Middleware\PreventRequestForgery;

Route::post('/webhook/stripe', HrrStripeWebhookController::class)
    ->withoutMiddleware(PreventRequestForgery::class);

Route::post('/api/internal', HrrInternalController::class)
    ->middleware(PreventRequestForgery::class);

Queue::route() for Dynamic Queue Routing

Route jobs to different queues based on their type or data. No more hardcoding queue names in every job class:

use Illuminate\Support\Facades\Queue;

Queue::route(function ($job) {
    if ($job instanceof HrrProcessLargeFileJob) {
        return 'heavy';
    }
    if ($job->priority === 'high') {
        return 'critical';
    }
    return 'default';
});

Cache::touch()

Reset the TTL on a cache key without fetching and re-storing the value. Simple but useful for sliding window patterns:

// Extend cache entry TTL by another hour without re-fetching
Cache::touch('hrr_user_session_' . $userId, now()->addHour());

// Useful for sliding window expiration
Cache::touch('hrr_rate_limit_' . $ip, 60);

Reverb Database Driver

You can now use your existing database as a Reverb backend instead of Redis. Great for smaller apps where you don't want to run a separate Redis instance:

// config/broadcasting.php
'reverb' => [
    'driver' => 'reverb',
    'storage' => env('REVERB_STORAGE', 'database'), // was 'redis' only before
],

Teams in Starter Kits

The Breeze and Jetstream-style starter kits now include Teams support out of the box. One flag and you're set:

php artisan install:breeze react --teams
php artisan install:api --teams

PHP 8.5 Closure Attributes

Laravel 13 uses PHP 8.5's new closure attributes internally. This enables cleaner attribute-based hooks across the framework:

// New in PHP 8.5 + Laravel 13 internals
$fn = #[SomeAttribute] function() { return 42; };

Each of these is a small win on its own. Together, they add up to a release that touches almost every part of the framework.

Collection of tools and equipment Photo by Tima Miroshnichenko on Pexels

Breaking Changes and Upgrade Guide

Now for the part nobody loves but everybody needs. Let's talk about what breaks and what you need to do about it.

Minimum requirements have changed:

  • PHP 8.3 or higher (PHP 8.1 and 8.2 are no longer supported)
  • Symfony 7.4 or 8.0

Here's a quick breakdown of the breaking changes:

Change Impact Fix
PHP 8.1/8.2 dropped Medium Upgrade PHP to 8.3+
Symfony 7.4/8.0 required Medium Update via composer
Model::unguard() removed Low Use $guarded = [] instead
Old Schedule kernel removed Low Move to route or attribute scheduling
assertStatus() strict mode Low Check test assertions

To upgrade, start with composer and then verify your tests:

# Upgrade Laravel to 13
composer require laravel/framework:^13.0

# Run the upgrade checks via Boost (if installed)
php artisan boost:check-upgrade

# Run existing tests to find breaking changes
php artisan test

# Check for deprecated usages
php artisan about

The impact here is moderate. If you're already on PHP 8.3 and your tests pass, you're probably fine. The Model::unguard() removal and schedule kernel changes are easy fixes. And if you installed Boost, the upgrade prompt can walk you through the rest automatically.

Laravel 13 is a clear signal that the framework is moving toward AI-native PHP. The AI SDK, vector search, and MCP server aren't experiments. They're first-party packages with long-term support. Taylor and the team are betting that AI features belong in the framework, not just in third-party packages.

Hope you enjoyed this rundown of Laravel 13. There's a lot here, and I'll be writing deeper dives on the AI SDK and pgvector integration in future posts.

Follow me on Twitter/X for more Laravel and PHP content. Drop a comment if you've already upgraded or if you have questions.

Get the next note

I email when a new post goes up. One send a week, and only if there's something new.

Want this applied on your account? Start with DevOps.

Related reading

More posts, sliding underneath the article

Kept below the post instead of in a sidebar, with a slow continuous motion for a cleaner editorial feel.

On this post

Comments

A reply stays under the note it answers.

0 comments

No comments yet.

If you have a note on Everything New in Laravel 13: The Complete Guide, sign in and leave it.