Taylor Otwell "Laravel Herd, Laravel 11, Laravel Folio, Laravel Volt" - Laracon US 2023 Nashville

In his Laracon US 2023 keynote, Taylor Otwell reflects on Laravel's growth, recaps 2023 product releases, and unveils four major announcements. He introduces Laravel Herd, a menu‑bar macOS app that bundles PHP, Composer, the Laravel installer and a Valet‑style auto‑detection system, removing the need for Homebrew and simplifying local development. He then previews the upcoming Laravel 11 skeleton, highlighting a leaner directory structure, removal of the HTTP and console kernels, migration of middleware configuration to the bootstrap file, method‑based model casts, a config‑cascading system that defaults to environment variables, opt‑in API and broadcasting routes, sub‑minute scheduler granularity, and a new weekly release cadence. Next, he demonstrates Laravel Folio, a page‑based routing package that maps Blade files in a `pages` directory to URLs, supports wildcard segments, route‑model binding, scoped child bindings, and can coexist with traditional routes. Finally, he showcases Laravel Volt, a functional, single‑file Livewire 3 syntax that lets developers write stateful components directly in Blade templates, with examples of a counter, a to‑do list, live search, and query‑string state. Throughout, he thanks the Laravel team, highlights recent improvements to Forge, Vapor, Envoyer, Nova, and the marketing page aimed at frontend developers, and announces that Herd ships today, while Folio and Volt launch next week and Laravel 11 ships later in the year.
Chapters
All right. Hey, everyone. Wow, it's crazy being up here again and seeing everyone here after 4 years of not having an in-person Laracon. It's really good to be back. And thank you for your support of this event. It was really an overwhelming response. Yeah, so thank you for that. How many people are here from your very first Laracon? Oh my gosh. It's like over 90. That's crazy. So that's actually really encouraging for me because that means there's a lot of fresh faces coming into the Laravel world. I don't want it to feel like stale and like it's kind of the same old crew every year. We're not really growing. So thank you for coming out. That's really cool. Thanks again to the sponsors and everyone, the event staff that made this event possible. They've done a really good job. And I've been building Laravel for 12 years now at this point. I believe this is my 18th official Laracon presentation, counting the European, the Australian, and now Laracon India conferences. And honestly, I've been loving every second of it because I still believe that Laravel is the most productive way to build full-stack web applications in the world. And a lot of that is because of you, because you write awesome blog articles, you make awesome YouTube tutorials, you write really cool packages. So thank you for that. I'm still loving working on Laravel, like I said earlier during my intro, and I look forward to working on it for a long time to come. And 2023 has been a busy year so far for us. And before I get into sort of the demo of my talk, I wanted to kind of give you a quick recap of some of the things we've done this year. The first thing is we launched Laravel 10 back in February, I think. Laravel 10, one of the big features was throughout our entire skeleton, We included method signatures— Return types. For every file in the skeleton, basically bringing Laravel up to date with all of the type hinting features that have been released to PHP since we initially wrote the framework back in late 2010. So we may continue to explore that in the future. The only thing remaining is adding property type hints to, like, for example, your Eloquent file by default. The only reason we didn't do that in Laravel 10 is that is unfortunately a breaking change. Every application would actually have to go in and add those property types. Which was a little bit more than we wanted to bite off in 2 at that point, but we may explore that in the future. It also brought the release of Laravel Pinot, our feature flag library written by Tim McDonald, who is here at the conference and will be speaking tomorrow. Laravel Pinot is sort of a painless way to manage feature flags in your application. You can store them in the database. You can use the cool lottery class that Laravel offers you to decide which users have access to specific portions of your application. So you can offer like a new API to some VIP customer and try it out without exposing it to the rest of your application's users, which is a really cool way to develop applications actually and beta test. We also launched our process interaction features, which Nuno Maduro and I sort of paired up on some, making it really easy to control external processes from Laravel Even controlling concurrent pools of processes that are processing a lot of data at one time and then handling their output in this really convenient, nice way that has a really good developer experience. We shipped Laravel Precognition, another one of Tim McDonald's brainchilds. And it's a really cool package. If you haven't used it yet, I would definitely check it out. And I feel like it especially shines if you're using Laravel Inertia because it lets you reuse all of your backend validation logic that you maybe have in like a form request. And it lets you reuse all that from your frontend without having to duplicate it all in your client-side code. So what happens is it actually runs all that validation, but it doesn't actually invoke the controller that is about to be invoked. And instead, it just returns all that validation data to you on the frontend. But I'll let Tim dive into that tomorrow because that's literally what his talk is focused on. We also shipped optional Pest scaffolding in the Laravel skeleton. Pest, of course, as many of you know, is Nuno Maduro's testing framework that has a really good developer experience, really expressive syntax. We made that an optional built-in feature of Laravel that you can add on when you create your Laravel application. On our commercial projects, we've continued to bring a number of UI improvements to Laravel Forge, which continues to be our most popular product. Thank you for your support of that product, which lets us sustain this whole open source Laravel development endeavor. We've shipped a ton of features to Laravel Vapor. I was just talking with Joe about this backstage, but we have honestly shipped just crazy amount of stuff, including failed job management directly from the Vapor UI, improved log search directly from the Vapor UI, ARM support, which brings increased performance while at the same time reducing costs, which is a total win-win. And of course, dark mode, you know, the most important thing of all. And just last week, actually, Joe and I shipped out this new visual refresh of Envoyr, which is our zero downtime deployment tool in Laravel. And Joe did a really good job on this redesign and sort of facelift of this product, which I'm really happy with. And we'd love to continue to make improvements to this product as well. well. Behind the scenes, we've also launched infrastructure upgrades to both Forge and Envoyr. We're running on much beefier servers now, much faster servers, so we can handle even more deployment capacity and provisioning capacity for your servers. We've continued to ship weekly features to Laravel Nova. Go check out the changelog for Laravel Nova if you don't keep up with it. Like almost a weekly basis, it's like over a dozen things that get shipped to Laravel Nova. And it's easy to lose track of what's all going into it. So go read that over if you haven't in a while, because there's some really cool stuff that's gone into Nova lately, including our new repeater field, which just launched within the last month or so that lets you add sort of multiple line items to things all from the Nova interface. And David Hemphill is my partner on Laravel Nova, and he's here as well. So reach out to him if you have any Nova questions. We've also been doing a little marketing, which is something we actually don't spend a lot of time focused on because we're always coding and building things. But we launched a brand new page pitching Laravel kind of to people who are more accustomed to frontend development. Maybe they've spent a lot of time in React or a lot of time in Vue or Svelte or Next, and they want, or maybe they feel like they need something more full stack. And the purpose of this page, which is at laravel.com/frontend, is to pitch Laravel and why I think it's the perfect choice for a full stack web framework to pair with something like React or Vue. And the reason for that is that Laravel— there's a fly up here— Laravel is a very batteries-included framework, which is in contrast to some other ecosystems, right? Especially the JavaScript ecosystem. So JavaScript ecosystem, really great at frontend stuff, but when you start to do full-stack backend stuff, you sort of have to piece together tons of different packages to make everything work. Like, you know, your ORM, sending emails, queuing jobs. It feels very disconnected. And so we're trying to show that Laravel is a viable choice, you know, in 2023 because it's so batteries included, it's so robust, it has such a rich ecosystem of packages developed by the community. So we're trying to advertise that a little bit. And we also highlight the 2 primary ways of building modern, highly interactive front ends with Laravel, Inertia and Livewire. And we demo this right on this page. And I consider these 2 packages to sort of be the backbone of modern Laravel's frontend development story. I want Laravel to be an amazing choice for frontend development, no matter what your preferred technology is. So some frameworks, they like go really hard on, we hate JavaScript, we don't want to write a line of JavaScript. And other frameworks, they go really heavy into the other way. Like if you're not writing React, you know, you can't work with this framework. So we try to play a balancing act where if you like React and Vue, Inertia is a perfect fit for you because it pairs your Laravel backend with your React or Vue frontend in this really awesome lean way that lets you lean on all your Laravel knowledge and server-side routing and Eloquent ORM while writing your frontend in React or Vue or whatever else. Inertia was a product or a package originally developed by Jonathan Riddick. And earlier this year, I reached out to Jonathan, who now is a partner at Tailwind Labs working at Tailwind, working on Tailwind CSS. And I offered to Jonathan to let us adopt Inertia sort of into the Laravel ecosystem and help you maintain it. I'll, you know, revise all of the documentation for you. And so a few months earlier this year, I wrote all the documentation, revised it, brought it like up to speed with everything that had been released. And we sort of officially adopted Inertia as a first-party package, you might say, in the Laravel ecosystem, which I'm really happy about. So we can ensure that it's continued to be maintained and developed for the community. And we released Inertia 1.0 earlier this year. And Laravel Breeze, our simplest starter kit, lets you scaffold applications with Inertia or Livewire. And we just launched TypeScript support earlier this year in our Breeze starter kit. So if you're using React or Vue, you can pass --typescript when you create a new Breeze application and you'll get a nice modern TypeScript React frontend to pair with your, you know, batteries-included full-stack Laravel backend. So if that's your thing, check that out. Another great way to write frontends with Laravel is using Laravel Livewire, developed by Caleb Porzio, who's going to be sharing some awesome new stuff with us tomorrow. I'm sure many of you have enjoyed this package. Who's using Livewire here? Woo! Okay, a good number of you. Livewire lets you build amazing modern applications using PHP and Blade, But the applications feel really dynamic and snappy and interactive, like they had tons of JavaScript behind them, when really you're just writing PHP and Blade the whole time. And you don't have to deal with any complicated build steps or frontend scaffolding and tools like that or whatever. So it's really fast development cycle, really nice, really slick. And I believe, like Inertia, Livewire should be considered a first-class citizen of the Laravel ecosystem. It's Blade templating, but it's supercharged with all this cool interactivity. And when Caleb launches the Livewire 3 site tomorrow, I'm really happy we're going to be launching it at livewire.laravel.com. And we want to continue offering our support to Caleb and his work on Livewire however we can. And so we're sort of considering this a first-class package in the Laravel ecosystem going forward, because I think it's that foundational to how we build Laravel applications. And for the Laravel framework in general, every week, you know, we continue to make improvements to the framework. And go out and look at the release notes on GitHub every week, and you can kind of stay up to speed with what we're putting out there. Even like last week, as you heard earlier, we released sub-minute granularity for scheduled tasks, which is a really cool new feature that Jess worked on. And we ship honestly cool new features almost every week. So go check out those release notes. to stay up to speed. So that is our sort of recap of 2023. And I'm going to transition to more of kind of demo mode now. So I'm going to close out this presentation. And first, I want to talk about how people get started with Laravel. We've tried to make getting started with Laravel as easy as possible through our documentation, through our starter kits, through, You know, all of the LaraCast material we've put out. But none of that is any good if you don't have PHP installed, you don't have a web server installed. And we've built things like Laravel Sail and Laravel Lay that make that easier. But we think it could be even easier yet. So I took a pretty risky move when I started this demo in that I don't actually even have PHP installed on this laptop. And this is my main work laptop. So probably the riskiest live demo move I've ever done. But we've partnered with Beyond Code to get back to basics. So Beyond Code, Marcel and Dee and the rest of the team, they built an application for us sort of at my request. And it makes it so easy to get started with Laravel and PHP because I want to be able to share Laravel with such a wide audience and I don't want there to be any barriers to entry to getting started. with this framework. So we're calling it Laravel Herd, and I'm gonna show you how it works. So again, I'm gonna open up my terminal. We can see that I literally don't have PHP installed, but I have downloaded Laravel Herd. So I'm gonna pop open the installer. I'm gonna drag it to my Applications folder, and then I'm gonna open it up. Cool. All right, and when I open it up, I'm going to get an installation wizard. It's going to ask me some questions. It's going to notice that I previously was using Valet, and it's going to offer to migrate all my Valet settings to Laravel Herd. I'm going to continue through that. And then I'm going to say automatically launch at system startup. And that's it. So let's pop open my terminal again. Cool. And you can see I've got Herd PHP installed. I've got the Laravel installer. And I've got Composer. Just that simple. Now, here's the really cool thing. This is not using Homebrew. This is not using any package managers. Everything you need is bundled into Herd. So it's powered by the same project auto detection that's in Laravel Valet. So if you have a Laravel project and it's in a certain directory that you specify, which we'll see in a second, it just works. If you have a Symfony project, it just works. If you have a Magento project, it just works. So it's really, really slick. All right, let's go ahead and open up some of the settings in Herd. So Herd is a menu bar application and it lives, you know, up here in my menu bar, as you would expect. And it has some settings, and I can look at the Nginx and DNS mask and FPM settings. But I'm going to go ahead and actually open up the full settings window. And this is really cool. This is where I configure my herd paths. So this is just like valet paths. So anything in these directories will be automatically detected, and I can just access them on my browser. So, for example, I have a Laravel project. So if I go to Laravel test, it just works because it's in my code directory. And if you've used Valet, this is no surprise to you. And this— you're used to this sort of behavior. In my sites tab, I can see what version of PHP each site is using. I can change that version. I can use SSL. And one of my favorite features is on the PHP tab, I can install additional versions of PHP. And what's really sweet, and if a new version comes out of PHP, even a patched version of the one you're using, let's say 8.2.8 comes out, my menu bar of Herd will have a little red dot, and I can just update to that patched version right there. Again, no Homebrew, no package managers, nothing. It just all works right here in Herd. There's an Expose tab where I can share my— Yeah, thanks. There's an Expose tab where I can share my site with the world. Very similar, like if you wanna show a site to a client that's on your local machine, you can share it using Expose and give them a public URL to see that site, which is on your local machine. So it's a pretty simple app. I will be eternally grateful to Marcel and the Beyond Code team for developing this app. I have wanted this app literally for many years. And so thank you to them for building this. We are launching this today. So— Woo! At herd.laravel.com, you can download this. This is, honestly, I consider this a gift to the Laravel community, to the PHP community at large, honestly, to make onboarding onto PHP as easy as possible. And it's totally free and you can download it today. So that is Laravel Herd. And thanks again to Beyond Code for building that awesome app. Now let's jump into some code. I'm going to pop into a project. And I wanted to show you a little preview of what we've been tinkering around with for Laravel 11. So Laravel 11 will land later this year. And I've been focused on streamlining the default Laravel application structure over the last few weeks, making it more light, more lean, more modern. And what's cool about this is there's actually not a single breaking change. So you're going to see a lot of things in this demo that look like they should be a breaking change, but it's really not because the framework is so flexible in terms of how the skeleton is structured that you can upgrade your Laravel 10 app to Laravel 11, change nothing about how your application is structured, and everything will work totally fine. What I wanted to show you today is just some ideas we've been playing with for what new Laravel 11 applications will look like. And this is just a preview. You know, don't get married to any of these particular ideas. This is very beta. Some of it may change. There may be some stuff that's reverted, some stuff that's added. But this is just kind of me sharing what we've been working on the last few weeks. All right, so let me hop into the controllers directory and just start kind of small. So the default controller in Laravel 11 actually doesn't extend any other magical controllers. This is a plain PHP class. And secondly, you'll notice within the HTTP directory, there's not even a middleware directory at all. So Laravel skeleton over the years has gotten a little bit bloated, I would say. And when I revisited it with fresh eyes, I was like, wow, there's a lot of concepts here. There's a lot of files here that feels a little bit overwhelming. And a lot of it you don't actually need to get started using Laravel. So for example, the Laravel skeleton previously had 9 middleware. Many of them you would never customize. So, for example, the encrypt_cookies middleware. It's there to encrypt your cookies when they come in, you know, from a client request, and it encrypts them on the way back out. But the only reason you would ever customize this middleware is if you needed to add a cookie to the config in the middleware that should not be encrypted for whatever reason, and that is extremely rare. So, for all of those middleware that had those little configuration options, You can now just configure that in an app service provider. So in the boot method, for example, I could just say encrypt cookies except some cookie. So if you need that, you can just do it there. We don't have to have this entire extra file in your application that you don't really ever need to customize. And similar methods exist for other middlewares like trim strings, validate signatures. Middlewares, they're important, but usually don't need to be customized by the end user. You'll also notice there's no HTTP kernel in the HTTP folder. I hate the word kernel in Laravel. I think it's like super enterprise Java sounding. I just did not want it in the skeleton anymore. So it's not there. It was sort of leftover technical terminology from our migration to Symfony HTTP Foundation. And most of the things you would do in the kernel, you can now conveniently do during the app bootstrap process. So for example, something you previously would've done in the kernel is maybe like register a middleware in your web middleware group. So what if I want to do that now? So let's just generate a middleware. Make this a little bigger for you. Artisan make:middleware Laragon middleware. All right, so it makes the middleware. And now in the bootstrap app file, there's a little bit more functionality in this file than there used to be. I think of it as sort of like a lean routes-esque style file for configuring Laravel, and you can do a lot of cool stuff in here. So in this with middleware function, I can just say middleware web append Laragon middleware, and I'll import that class. And if we go to that middleware, I'll just dump out something. All right, and now if we hit our example application, we see that we hit that middleware. So the things you used to do in the kernel can just be done a different way, and we can add middleware, we can remove middleware, we can substitute middleware, we can even define entirely new middleware groups right from that file. And if you're just in love with the HTTP kernel, you can bring that back into your application as well. But this is just a simple streamlined way to interact with that kind of stuff. All right, let's go back to our application. Let's jump into the models directory. The models directory, or the model in this directory is not really that much different, but one thing I wanted to show you is that casts are now defined as a method instead of a property. And why is that cool? How is that not just a pointless change? And the reason that's cool is because when we define it as a method, we can do really nice stuff like call other methods from our cast method. So let's imagine I have an array of options in my users table, but it's actually a collection of enums. in my application. So our asEnumCollection cast actually has a helper method where we can say asEnumCollection of UserOption, and we can do this really expressive cast declaration that isn't possible in a PHP property, because when you define properties, you can't, like, call methods like I just did from that property definition. So by making the cast a method, we can call other methods and sort of have a more expressive syntax for assigning casts. into your model properties, and it just reads better, it looks better, you get better IDE support and stuff like that. I think it's a pretty nice little improvement, but not a huge change to models other than that. What about configuration? And hopefully this is where you don't get up and leave the room. In Laravel's current application, there is a lot of config files in the current skeleton. And how many are in this skeleton? Well, let's pop it open and take a look. There's actually nothing in the config directory. So the config in Laravel 11 actually cascades down into the default set of configuration options for you. And the environment file has also been expanded to include more options for most every configuration value you'd want to set. You can do it right from your environment file. Now, what if you really want a config file? Because there is helpful documentation in some of these config files. You may not be aware of the options. There is a new config publish command. So if I do artisan config publish, for example, database, I get the database config file and it looks just as you're used to. But what's cool is I don't really need to keep any of the options I don't want. So if I only care about maybe this, this first option, I can just delete the rest of the options in the file and they'll all use their default values and inherit their values from the environment file. But I can customize this value, and it will take precedence over the default values. And if I want all of the config files, I can just run artisan config publish with no arguments. And now I'm pretty much back to Laravel 10 style, you know, beefy config folder with everything possible, and I can dig through it. And again, I could always go back through and delete the files I don't need later, but this lets me see everything right at my fingertips. All right, so that is config in Laravel 11. The migrations file, just a very minor change here. So previously, when you create— or currently, actually, when you create a new Laravel 10 application, the default migrations say 2014 right in the front of the migration. So what better way to advertise Laravel has been around a while than to put 2014 in the default migrations? And I thought, you know what? That just kind of— That's a little dated. That kind of seems— let's not advertise that right out of the box. So I've just renamed these files to be kind of evergreen dated to year 1 so that they always run first. And it's very obvious these are just like the default migrations and we don't date ourselves immediately upon creation of a Laravel 11 application. We've also kind of consolidated these migrations. So like the users table and the password resets table are both just in this create users table. migration, and the jobs table and the failed jobs table are both combined into this one jobs migration. So we kind of trimmed off a migration there to slim it down just a little bit further. All right, let's pop open the routes directory. So by default, you'll see there's only 2 routes files, console and web. And that's because many applications actually never offer a public-facing API. And yet you have this API routes file, you have Laravel Sanctum in your default application for personal access tokens. And honestly, it's probably rare that, you know, we have applications issuing personal access tokens. So we've decided to remove those by default and make that opt-in. So how do I opt in? I love APIs. So let's make it super easy. I'll go to my command line. All I have to do is do artisan install api, and that gets me the API routes file. It installs Laravel Sanctum. And I'm ready to go, just like I would be in Laravel 10. And here's my API routes file. I could see us expanding this command a little bit in the future. So I could imagine a situation where we have the install API command, and there's also a flag to tell it to remove all the frontend stuff entirely. So I'm not gonna have any views, I don't want any Vite config, I don't want any Tailwind stuff. I'm only building an API. I could see us improving the install API command to handle that for you as well. And the same with broadcasting. If I'm using Laravel Echo, I have broadcast channels, I need a channels/routes file, I can just do artisan install broadcasting, and everything is installed for me. So a little bit more opt-in, really easy to get back these files if you need them, but they're not in your face in a default Laravel application, because again, most applications may not have a public-facing API, most applications may not be using WebSockets. So very easy to opt back in, though. So CLI routes file. So like I said, there's no HTTP kernel. There's also no console kernel in the default Laravel application structure. So that means you can define your scheduled commands right here in your console routes file, just like your web routes file. It feels very light, very declarative, very functional. And I can just declare those commands right there. I can take advantage of the new sub-minute granularity for the scheduler and put them right there in my routes file. And so what if I create a class-based command? It works just like you would expect. Artisan make command Laragon command. It puts it in app/console/commands. I can just write something out to the terminal here. And I don't really have to register anything. the app laragon command will already be available. So if I do app laragon command, Laragon. So zero registration. I can just make commands, start using them. No console kernel, nothing like that to complicate things. So that's kind of where we're— I'm at with the Laravel 11 skeleton right now. We have more ideas we'll continue to work on in the future. Please give us your feedback. What What do you love about the Laravel skeleton? What do you hate about the Laravel skeleton? How can we make Laravel more intuitive, more easy to use for newcomers so it doesn't feel overwhelming when you first get started? But I think it feels really light, really lean, really modern, and updated. So that is the Laravel 11 preview. Thank you, Taylor. So we've also been exploring ways, totally new options for how you build your Laravel applications. We previewed early versions of these tools at Laracon India. They've changed a lot since then, hopefully for the better. And today you'll get to see them basically in their final form. And first, I want to dig into a package called Laravel Folio. So I'm going to switch to that branch. Cool. I'm going to close out some stuff here. All right. So if you've ever used a frontend framework like Next.js or Nuxt.js, you know they primarily use something called page-based routing. So they don't have like a routes file like we would be used to where you list all the URLs your application responds to and how they— what kinds of things they respond. Basically, they'll have a pages directory, and when a URL or a request comes into the application, they'll look through the pages, and they'll find the matching page, and it will just automatically route to that page. And that's actually super convenient. It's a really fast development feedback cycle. You don't have to write any routes. You don't have to make any controllers. You just drop a template in this pages directory, and you hit it in your browser. Boom. Done. So it's super, super nice and easy. And that's basically what Laravel Folio brings to Laravel, that same page-based routing option, and I'll show you how it works now. So let me go ahead and start up my development server, just so our CSS is kind of compiling as we, as we make changes. In our views directory, I have a pages directory with some pages. Now if I try to hit something in my application right now, I'm just getting a 404. So we need to tell Laravel where my pages are when I'm using Folio, and we can do that in my bootstrap app file. So I'm going to go in here and I'm going to add a line under commands in my with routing method. I'm going to say pages are at resources/views/pages. All right. And then I'm going to refresh this page and boom, we're here. All right. So how does Folio work? Well, as you might expect, it works based on a set of conventions for how your files are laid out. So let's pop open this directory structure. Get them side by side here a little bit. And you can see in pages there's an index.blade.php file. And that's basically the page we're looking at right now. So if I hit the application with nothing else in the URL, it's going to load the index.blade.php file in the pages directory if I'm using Folio. All right, so you can see this is the page we're looking at. There's the markup. I can edit this page. And see the changes there. Everything's live updating. It's really nice. All right. But of course, we aren't limited to index pages. We can also see if I look at this directory structure, there's a schedule page. So as you might expect, if I hit this application at /schedule, that is the page that will be rendered. All right. So automatic page-based routing. Now let's look at the users directory. In this users directory, you can see that there's an index.blade.php file in that directory as well. So what does that mean? Basically what that means is if I hit /users and it sees there's a users directory with an index page, it says that's the page that should be rendered. So if I go to the users URL, you can see now we're on the user index. And I'll pull that up here in Sublime Text. And you can see at the top of the file, I'm just making an Eloquent query. And then we're just displaying out the users. Let's just keep things really simple for now. But really easy page-based routing. I can throw an Eloquent query in there if I need to. Now, you might be wondering if you saw my directory structure, what is this file right here with this weird bracket syntax in the file name? And you know when you build a Laravel route and you say like slash curly braces ID to capture sort of a wildcard segment from the URL? The URL might be like /user/1. That's what this page lets you do. So the ID in square brackets says this is a wildcard segment. I want you to pass me the ID from the URL into this template, and I can use that ID at the top of the page to pull the user out of the database and show some information about it. So if I were to hit user/1, I get the ID, I pull the user out of the database, everything just works. But Laravel has a really cool feature called route model binding, where it will just give me the eloquent model that matches the ID in the URL automatically, and I don't actually need that query at all. And we can actually take advantage of this with Folio as well. So if I rename this file and change this to user, the name of the model, I can actually just delete all this PHP at the top. Refresh the page, and everything works. So of course, just like normal route model binding, if I try to access a page for a user that isn't in the system, such as like user 100, I get a 404 not found page, just like, just like you would expect in normal Laravel routing. So this is a wildcard page, but we aren't just limited to wildcard pages. You could also have wildcard directories. So let's kick it up another notch. I will pop open my sidebar here. And you can see that I have a talks directory, bracket talk, which is route model bound. And then I have feedback.blade.php. So the URL would be /talks/1 for the talk ID, /feedback. Does that make sense? So if you had, you know, talk/1/speaker, that would route to a speaker.blade.php file. In this directory. So, and again, since we're using route model binding, the talk is just available to me right here in the template. I don't actually have to run a query to pull it out of the database. So it's really fast and really easy to use. So for example, I think if I click on this talk, this will take me to talk/1/feedback. The page loads, the talk is injected, and we can just start rendering whatever markup we need to, and we can edit this page. Right here in the browser, everything updates. So really quick, really fast. But there's more to routing in Laravel. What about middleware? How do we get middleware on these pages? It's actually really simple. So I've created a TalkPolicy class for our authorization. And right now, it's just going to determine if a user can view a given talk. For now, I'm always returning true. So how could we use, for example, the Can middleware, which lets you authorize access to a route from our page. So let's go to that feedback page. And what we do is actually at the top of the template, we start a PHP block and we use a function called Laravel Folio middleware. All right. Then I'm going to say middleware can_view_talk. And this is just normal can middleware syntax that you can use on all of your normal Laravel routes. So if I hit the page, nothing changed because I'm allowed to view this talk. But if I go to talk policy, put false here, I'm not allowed to view the talk. So really easy to assign middleware to any of these pages and get the full power of Laravel's existing middleware system right there from your Folio pages. So that's some of the basic features of Folio. I have A couple more advanced things I want to show you real quick before we move on. The first thing is— let me go back to my home page here— multi-segment pages. So if I open up this examples directory under multi, you'll see I have a file name that's bracket dot dot dot IDs and close bracket dot blade dot PHP. So what happens is if I were to hit /examples/multi/1/2/3, All of the IDs would be given to this template in an array, and I could just implode them together, for example. So let's go ahead and click this example, and you can see that the URL is examples/multi/1/2/3. All of the IDs were gathered together into an array, injected into this template for me, and I can do whatever I want with them. So that's multi-segment routing. An even cooler advanced feature is scoped child bindings. I'm going to show you what I mean by that. If I pop open this users directory, we have a user route-bound directory, talks, and then we have a talk route model binding, but we have colon slug in the file name. So what that does is when I go to /users/1/talks/something, I can just put the talk slug. And I've assigned a slug to each talk. This is very common in, like, a blog where you go to, for example, blog.laravel.com/improving-forge or something, and the blog post has a slug for the title. So this lets you do that, but what's cool is when I access this page, Laravel will automatically make sure that the talk belongs to the user that occurred previously in the URL. So for example, if I go back to my homepage and I hit this URL, you can see we're at users/1/talks/self-aware, because that's the slug for this talk. And that talk belongs to user 1. But I know that the talk for user 2 has a slug of exploring-jupyter. And if I try to access that, I actually get a 404 not found, even though a talk with that slug exists. But if I change this to user 2, I can access this URL. So the scoping is handling— is being handled automatically. Laravel is verifying that the talk actually belongs to the user that occurred previously in the URL. So a little bit of a technical feature, but actually really nice and kind of saves you from doing some authorization in your code. And the final thing I want to show you with Folio is that just because you install Folio, you don't have to use pages for your entire application. So for example, I could come to my routes/web file. I can have some example routes, and I can just hit that in my browser. So it's not an all-or-nothing thing. There may be some parts of your application where it's like, hey, Folio would actually make this really nice and convenient. I think I'll use that for this subset of my application. The rest of my application I'm going to build using routes and controllers and all of that stuff that I'm used to. So that is an introduction to Laravel Folio, powerful page-based routing for Laravel without having to write routes or controllers. And we'll be releasing Laravel Folio to you next week. But it feels like Folio is missing something. And when I was building Folio, I felt this immediately. It's— Folio is great if your pages are relatively static. But how many of us are building totally static pages? If we were, we probably wouldn't need Laravel, right? We'd just be using something else. We could pair Laravel Folio with something like Nova to kind of have an admin backend where we can update the data. We can just use Folio to pull the data with really simple Eloquent queries. That would work to let us make Folio a little bit more dynamic. But what if we want to bake really rich interactivity into our Folio pages? Um, Vue people can do this, right? React people can do this because they have scripts with their template that let them build all sorts of complex interactivity. But how do we bring this to Folio? Well, like we talked about earlier, the Laravel ecosystem actually has a really great way to bring interactivity to Blade and PHP, and it's called Laravel Livewire, uh, which Caleb will be talking about tomorrow. So let's take our Folio demo to the next level by introducing another package developed by Nuno Maduro and myself called Laravel Volt. And I'm going to change to that branch now. All right. I think the easiest way to show you Volt will be to just create an entirely new page for ourselves to work with. So let's close out some of that stuff. All right. So I'm going to make a new page called Volt. So I'll go to my command line. I'll do artisan make Volt. Oh, that's cool. Folio Vault, which will generate a new page for me. I'm going to just kind of stub it out here with a blank page. Let's see if this works. All right, so this is just a blank Folio page to get started with. And if you've ever used Vue and React, you know that your components' logic and their markup live in the same file. And this is a concept called code colocation or locality of behavior. And it's a really convenient concept, even though at first, from maybe like traditional programming advice of years past, it may sound kind of repulsive. But it's the same concept in tools like Tailwind CSS that put all of the utility classes in your markup, which seems like really counterintuitive at first. But once you start using it, you're like, wow, this obviously makes way more sense and is way more productive. And that's because the behavior in the code kind of change together and live together. And you don't go to a totally separate file to change things and have to come back and look at a different place to see what kind of CSS selectors you're hooking up to and what other parts of the application it affects. It actually ends up being a really productive experience to just have everything together. And what Laravel Volt is, is an optional add-on for Livewire 3 that lets you write beautiful single-file Livewire components right in your Blade templates, just like a React developer would with React, or just like a Vue developer would with Vue, but in Blade and with Livewire and in Laravel. Now, in this demo, I'm going to be using Volt paired with Folio for most of the demo, but you do not need to use Folio to use Volt. They are 2 totally separate packages. They just happen to work really well together in concert, I think. But if you hate Folio, you can still use Volt in your normal Laravel application. So, So keep that in mind. Let's dive into a Volt component and let's just build a really simple Volt component to get started, just like a counter or something. So I'm gonna actually put a Livewire component here called counter, and we're just gonna kind of build this from scratch. So in my Livewire directory, I'll make a new file called counter.blade.php. Let's just kind of stub it out here. I'll just put counter here. And now that we have that on the page, can we refresh this? Okay, there's our Livewire component. Let's start adding to it. So first let's have like a current value. We're just gonna have a counter that we can click a button and increment, you know, 1, 2, 3, 4, 5. So we know we need some state to store the current value. If we were using Livewire, we would declare that as like a public property on our class. But again, Volt brings a functional API to Livewire. So what does that look like? So let's say current value, just close that. Current value, we'll dump it out. Now at the top of our template, we'll start a PHP block. And again, we're going to import a function, Laravel Volt state. And we're just going to say state current value is 0. All right, let's go ahead and refresh the page and see what that looks like. Cool. Looking good so far? So let's build the increment functionality. I'll just wrap this in a little div real quick. I have a Blade component button that I've written just so we can have a nice button here. What do we need? Maybe some margin, wire click, we'll call this increment. So just normal Livewire markup, nothing weird here. We'll say, Increment. OK, so we've got that wired up, but we haven't actually defined the behavior yet. How do we do that? Super easy. Increment function. Just increment the current value, just like that. I'll refresh the page, and our component is working, just like that. So that's all it took to build a stateful counter right here in our Blade template. This is compiled to a normal Livewire component behind the scenes. I can use it in any Laravel application. Doesn't matter if I'm using normal routing or Folio. It doesn't matter if I'm mixing and matching class-based Livewire components with Volt components. I can use it in any Livewire 3 project if I feel like it would benefit from this functional API. What about something with a little more meat on it? We could build something like a to-do list, of course. Let's replace this counter with a to-do list. So I'll go back to my Volt page— not print. Go back to my Volt page. I'm going to replace this with todos. And we're going to make an entirely new component here. And I've already stubbed out a little bit of this. Just to save us some time here. All right, so I'm going to drop that in. We'll explore that in a second. Refresh the page. All right, looks like we're good to get started here. So this is a simple to-do form. It has the text box, an add to-do button, and then down below it's going to list our current to-dos. But I haven't actually hooked any of this up yet with any interactivity. I've just put the markup in place to save us some time. All right, so how can we get started? Well, If we look at the top of the page, you can see I've just initialized todos to an empty array so that the page would load. So first, why don't we start pulling todos out of the database using Volt and Livewire? I'm gonna refresh my database to get it ready to go with my todos table, and let's start building this Volt component. All right, I'll start our PHP block. Now if we just wanna provide some data to the template, which would basically be the equivalent of passing the data to the view call in the render method of our Livewire component, I can just use the provide function that is given to us by Laravel Volt. So use function Laravel Volt provide. I will call that function, give it a closure, and this is the data we want to make available to this template. So in this case, todos, we'll just pull them all out of the database. All right. So I'll save that. We shouldn't really see anything change here, which it hasn't, but we are actually invoking this behind the scenes to get those todos from the database. All right, next let's hook up our form so we can actually put something in the database. All right, so to make this happen, we'll need some state again. We have this text box where we're gonna put the title of the todo. So we're just gonna hook that up just like we're used to in Laravel Livewire. So I can say wire:model, we'll call it title. I'll put that there. And now we need to hook that up to some state. I will import the state function, and let's just initialize the state to an empty string. All right. Let's refresh the page. We are still good. We can make sure that it's actually hooked up correctly by— I will just drop .live on this and dump it out down here. And now if I type in here, it appears over here. So everything appears to be working correctly. We have hooked this up to Livewire. I'll go ahead and remove that. All right. So now we need to actually add the todo creation when our form is submitted. So let's hook that up. So wire submit prevent add. All right. And we'll just go up here and define a closure. Add equals function. We'll say todo create. Normal Eloquent stuff. Oh, that's right. title, this.title, and then we'll reset the text box to an empty state once we've saved the todo. So that looks pretty good to me. Let's go ahead and try it out. First todo, second todo, third todo. Great. So we've hooked up this form to Livewire right here in this single file component using a really nice functional API. All right, next we could add in some validation. So maybe we wanna validate that the title is provided or that maybe there's a certain amount of characters in the title. That's also super easy to do. We could hook into all of the stuff Livewire already gives us because behind the scenes this has just turned into a normal Livewire component. So let's import the rules function. Let's say rules title. Required min 3. And then down here we'll just call this validate, normal Livewire method that's provided to you even when you're not using Volt. You can call it from any of your component methods to run your component's validation rules. All right, so let's give that a shot. I already have a little error message component down here that will render the error message if there is one. So we should be able to try this out right away. If I hit add todos, title field is required. If I try to put in a todo, it must be at least 3 characters. And of course, if I put in a valid todo, everything just works. So super easy to add validation in Volt components. And of course, we could have called validator make inside of this closure. We could have done whatever we want. This is just a normal Livewire method where we can do anything that we would normally do in Laravel. All right, so let's go ahead and finish this example out by deleting the todo. So I'll go down to this delete button. Let's go ahead and come down here. We'll hook up a little wire click. Delete. We need to pass the todo ID into that delete method. And let's just go ahead and define that behavior. Delete equals function todo. Livewire will automatically inject that model for us. We don't actually have to pull it from the database. I can just say todo.delete, and we should be done. So I can start deleting todos just like that. Super easy. Super easy to use. And I love how fast the development feedback loop is when you're building Volt components, because everything is right here in the file. Everything can honestly be live updating if you're using our Vite development server. It's really quick to develop things, really quick to get feedback for maximum productivity. And Volt supports all of the features coming in Livewire 3. Caleb's gonna show you a whole slew of new Livewire features tomorrow. I'm not gonna spoil any of that, but just know that Volt is ready for all of those features on day 1 when we release Volt next week. All right. And before I wrap up, I want to show you just a couple more goodies that Laravel Volt gives you. So let's go back to that user index we had a little bit earlier in our Volt demo or in our Folio demo. So I'll go back home, users, and let's kind of play with this page for a little bit. So sometimes it would be really nice to add a little bit of Livewire to a page, but I don't really want to like extract out another component. I just want a small part of this page to become a Livewire component. Because typically, like, let's say I want this user list to be interactive in some way. Maybe I want it to poll for new users automatically using Livewire's wire:poll directive. Typically I would need to, like, copy this part of the template out to another file, put it in my Livewire directory, and then replace this part of the template with, you know, angle bracket Livewire colon user-index, and it would live in a separate file. Sometimes I just don't want to do that. And Volt lets you get away with it. So I can just do Volt user index in Volt. And now this is a Livewire component. Just that part of the template, not the whole layout or the header or anything like that. Just that snippet of HTML within the Volt directives is now a Livewire template. So let's start building that component. We're gonna get the users out of the database. So use function Laravel Volt provide, invoke that, and let's go ahead and grab all those users and import that class. All right, we shouldn't really see anything change here, I don't think, and we don't. We're still just getting the users out of the database, but this is now a Livewire component. So if I come down to this So if I go into this div and do wire pull, I'm going to refresh the page, and I actually have an artisan command to create new users. Artisan create user. And you can see that the new users pop up on the page automatically. So just like that, we've converted that small part of the template into an interactive Livewire component that we can build with without even extracting it into the Livewire directory at all. It's really magical, but honestly, a really good kind of magic, I would say. Really fun. So let's add one more thing to this. Maybe we want a search. We want to be able to search for a user. I'm going to go ahead and start adding that to that Livewire template. So I'm going to wrap everything in sort of a root div. I'll come in here, and let's add a little search box. text input. Maybe we have placeholder search. We're going to hook it up to wire.model.live.debounce. We're going to hook that up to some search state. I think that should be pretty much all we need there, so I'm going to save that. Let's go ahead and define that state. State, state search as an empty string to begin with. And we need to modify our query, right, because we're not actually hooking into that search term to determine what users to return. So let's go ahead and do that. So if the search is empty, we will return all of the users, just like we're doing now. Otherwise, we'll say where name like this search. And it should look pretty much like that, right? So let's go ahead and give that a shot. I'll type in Casey. Ooh, I got nothing. What did I do wrong? Forgot the GET. I forgot the what? Yeah, I mean, because there was like a— The GET. Y'all are geniuses. Total geniuses. Now we get Casey. All right. All right, so I'm going to go ahead and remove this polling. I don't want that to mess up with my demo here. So now we have this really cool live search that we can use to pull users. You know, I can search for whatever I want, and it all just works really easy using a single-file Livewire component. And you can see, though, the only downside is if I refresh the page, I lose my search state. So again, Volt exposes all of Livewire's features to you. And one of those features is query string state in the URL hooked into your Livewire state. So what if I want, you know, when I type in a search string, I want to be able to send a URL to another person that already has like search in the query string and some of the characters, and that populates the search text box here on the page. Super easy with Volt. So I'll just come up here to my state. I can just chain the URL method onto my state. I can just refresh this page. Now I see Casey in the URL. When I refresh the page, Livewire automatically populates that backend, and everything works. And Volt components are just as testable as normal Livewire components. Caleb has already built really good testable— or testing helpers into Livewire, so If I come into, for example, this example test, I already have a snippet here for us. Let's see, I'll just paste that in. I can just say Volt test and then user-index. Even though this is like a fragment of a Volt component inside another page, I can just reference it by name. I can set some search state. I can assert that I see the user with that name and that I don't see some other user that doesn't have that name. And if I run these tests, hopefully they all pass, and they do. So very easy to test your Volt components. Just because you're using Volt, you don't have to give up any testability at all. And like I said, you can use Volt outside of Folio. So when we bring this out next week, you can start using this in Livewire 3 applications right away, and you do not have to change anything about your routing, your controllers. I want everyone to be able to enjoy this, and hopefully you you find it as fun to use as we have found it as fun to build. So that is everything I wanted to share with you today. Laravel Herd, a preview of Laravel 11's application structure, Laravel Folio, and Laravel Volt. Laravel Herd is available today. It's available right now. Laravel Folio and Laravel Volt will be available next week, and Laravel 11 will come this winter. In closing, I want to thank the entire Laravel team. Almost all of us are over here. We're only missing Mior, who helps us with Laravel Nova. But the rest of the team, they've all contributed so much to Laravel, and they've made it possible for us to build all these cool things. So James, Joe, Dries, Nuno, Guus, Jess, Tim, David, they're all here in attendance. I don't think we've ever had this many Laravel team members in attendance. Thank you to all of you for your work at Laravel. And in closing, thank you all so much again for your time. Thank you for coming to Laracon. I'll be around chatting with you as long as you want at the afterparty here on site, and I'll be at Laracon After Dark. Thank you.
More from Taylor

Everything New with Laravel and Cloud | Taylor Otwell Keynote at Laracon US 2026

In conversation with Taylor Otwell: The India Comeback - Hosted by Vishal Rajpurohit

Introducing Laravel VPS & Major Updates to Forge | Laracon Keynote 2025 (Taylor Otwell & Team)

Introducing Nightwatch for Laravel | Taylor Otwell & Jess Archer Keynote at LaraconAU 2024

Laravel Cloud, Inertia 2.0, VS Code Extension, & OSS Updates | Taylor Otwell Keynote | Laracon US




