Originals — posts I've written myself.

Typed routes from Laravel to React with Wayfinder original

by Freek Van der Herten – 3 minute read

I've been writing about There There a lot lately. It's a helpdesk we're building at Spatie, born from two decades of running our own customer support for our open source work and SaaS apps. After all that time being the customer of other helpdesks, we finally started on the one we actually wanted to…

Read more

Laravel AI SDK in practice: the agent behind There There original

by Freek Van der Herten – 5 minute read

Over the past few weeks I've posted a couple of times about There There, the helpdesk we're building at Spatie. After two decades of running our own customer support, we decided to stop compromising on tools and build the one we actually want to use. A lot of the fun is on the AI side. We're not…

Read more

Join 9,500+ smart developers

Get my monthly newsletter with what I learn from running Spatie, building Oh Dear, and maintaining 300+ open source packages. Practical takes on Laravel, PHP, and AI that you can actually use.

No spam. Unsubscribe anytime. You can also follow me on X.

Keeping Laravel and TypeScript in sync with data objects original

by Freek Van der Herten – 4 minute read

At Spatie we build SaaS apps with Laravel on the backend and Inertia with React on the frontend. That split means two type systems have to agree about every payload that crosses between them. Laravel data going out, TypeScript picking it up. There There, the helpdesk we're building, is built exactly…

Read more

Exceptions that explain themselves original

by Freek Van der Herten – 3 minute read

There There, the helpdesk we're building at Spatie, is a project of learned habits. Twenty-some years of writing Laravel apps has taught us which patterns pay off and which ones quietly rot. One that keeps earning its keep is a custom exception class for every domain error. This is a small pattern,…

Read more

Streaming AI replies from Laravel to React original

by Freek Van der Herten – 5 minute read

A couple of posts back I walked through the agent and tools we built on top of the Laravel AI SDK for There There, the helpdesk we're putting together at Spatie. I ended that post on a small cliffhanger. We hand the agent off to a streaming service that turns the SDK's response stream into events…

Read more

More Jev in There There: smart conditions and AI assignment original

by Freek Van der Herten – 4 minute read

Recently I wrote about how we use Jev in There There to detect spam, bounces, and automatic replies. Jev reads an incoming email and answers questions we define up front. We keep the probabilities and decide in our own code what counts as a match. The cheap checks on mail headers still run first.

That post ended with a promise that we'd find more uses for Jev. Here are two we have since added to There There: smart conditions for workflows, and automatic assignment to a team or person.

Read more

Announcing laravel-sluggable v4 with self-healing URLs original

by Freek Van der Herten – 5 minute read

The spatie/laravel-sluggable package has been around for close to a decade. A slug is the readable part of a URL that identifies a record, like announcing-laravel-sluggable-v4-with-self-healing-urls in this post's URL. The package generates one for any Eloquent model when you save it, derived from a title or another text field, and most of the time you don't have to think about it.

We just released v4, which adds a few things worth talking about. Let me walk you through them.

Read more

Generate Apple and Google Wallet passes from Laravel original

by Freek Van der Herten – 7 minute read

A mobile pass is that thing in your iPhone's Wallet app. A boarding pass, a concert ticket, a coffee loyalty card, a gym membership. Apple calls them passes. Google calls them objects. Both Wallet apps let you generate them, hand them out, and push live updates to the copy that's already on someone's device.

We just released Laravel Mobile Pass, a package that lets you generate those Apple and Google passes from a Laravel app and send updates to already issues passes.

Together with the package, we also published a demo site where you can create Apple Wallet passes and push an update so you can see it all working on your own iOS device.

Dan Johnson and I have been working on it for a while. Let me walk you through what it can do.

Read more

Instant view switches with Inertia v3 prefetching original

by Freek Van der Herten – 3 minute read

Over the past few months we've been building There There at Spatie, a support tool shaped by the two decades we've spent running our own customer support. The goal is simple: the helpdesk we always wished we had.

We care about using AI in a particular way. It should help support agents write better replies, not substitute for them. The human stays in charge of the conversation, and the model does the unglamorous work of drafting, rephrasing, and suggesting links. There There is in private beta right now, and you can apply for early access at there-there.app.

We're building There There with Laravel and Inertia, and we lean heavily on the latest features Inertia v3 brings. This post is about another one: prefetching on hover.

Read more

How we use Inertia v3 optimistic updates in There There original

by Freek Van der Herten – 4 minute read

A few months ago we started building There There, a helpdesk we're making at Spatie. The premise is simple. After two decades of running customer support for our open source work and our SaaS apps, we wanted the tool we always wished existed.

One thing we care about in particular is using AI to help humans craft better responses, not to replace them. The agent stays in charge of the conversation. The model just helps them reply faster and a little sharper. There There is in private beta right now, and you can apply for early access at there-there.app.

We're building There There with Laravel and Inertia, and we lean heavily on the latest features Inertia v3 brings. In this post I'd like to give one example: optimistic updates.

Read more

Scotty: a beautiful SSH task runner original

by Freek Van der Herten – 5 minute read

We just released Scotty, a beautiful SSH task runner. It lets you define deploy scripts and other remote tasks, run them from your terminal, and watch every step as it happens. It supports both Laravel Envoy's Blade format and a new plain bash format. Why we built Scotty Even though services like…

Read more

What's new in laravel-activitylog v5 original

by Freek Van der Herten – 6 minute read

We just released v5 of laravel-activitylog, our package for logging user activity and model events in Laravel.

In Flare, Mailcoach, and Oh Dear we use it to build audit logs, so we can track what users are doing: who changed a setting, who deleted a project, who invited a team member. If you need something similar in your app, this package makes it easy.

This major release requires PHP 8.4+ and Laravel 12+, and brings a cleaner API, a better database schema, and customizable internals. Let me walk you through what the package can do and what's new in v5.

Read more

Laravel Query Builder v7: a must-have package for building APIs in Laravel original

by Freek Van der Herten – 6 minute read

We just released v7 of spatie/laravel-query-builder, our package that makes it easy to build flexible API endpoints. If you're building an API with Laravel, you'll almost certainly need to let consumers filter results, sort them, include relationships and select specific fields. Writing that logic by hand for every endpoint gets repetitive fast, and it's easy to accidentally expose columns or relationships you didn't intend to.

Our query builder takes care of all of that. It reads query parameters from the URL, translates them into the right Eloquent queries, and makes sure only the things you've explicitly allowed can be queried.

// GET /users?filter[name]=John&include=posts&sort=-created_at

$users = QueryBuilder::for(User::class)
    ->allowedFilters('name')
    ->allowedIncludes('posts')
    ->allowedSorts('created_at')
    ->get();

// select * from users where name = 'John' order by created_at desc

This major version requires PHP 8.3+ and Laravel 12 or higher, and brings a cleaner API along with some features we've been wanting to add for a while.

Let me walk you through how the package works and what's new.

Read more

Laravel Site Search v3 is here: crawl and search your entire site using just your database original

by Freek Van der Herten – 5 minute read

We're proud to release v3 of laravel-site-search, a package that crawls and indexes your entire site. Think of it as your own private Google. Point it at a URL, let it crawl every page, and get full-text search results back.

Previous versions required Meilisearch as the search engine. That works well, but it means running a separate service.

With v3, your application's own database is all you need. It supports SQLite, MySQL, PostgreSQL, and MariaDB out of the box, and it's the new default.

Let me walk you through it.

Read more

How to easily access private properties and methods in PHP original

by Freek Van der Herten – 7 minute read

Sometimes you need to access a private property or method on an object that isn't yours. Maybe you're writing a test and need to assert some internal state. Maybe you're building a package that needs to reach into another object's internals. Whatever the reason, PHP's visibility rules are standing in your way.

Our spatie/invade package provides a tiny invade function that lets you read, write, and call private members on any object.

You probably shouldn't reach for this package often. It's most useful in tests or when you're building a package that needs to integrate deeply with objects you don't control.

Let me walk you through how it works.

Read more