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

Taylor Otwell announces Laravel's biggest updates: a VS Code extension with autocomplete and diagnostics, container attributes for dependency injection, chaperoned Eloquent models to prevent N+1 queries, the defer() helper for background work without queues, and Inertia 2.0 with async requests and lazy-loading components.
Chapters
Feels good to be back. It's been an awesome first day. Thank you to all the speakers. Thank you to all the sponsors for making this event possible. Before this talk, I was thinking, I think this is my 20th official Laracon talk. If you count Laracon US, Laracon EU, Laracon Australia, and now Laracon India. I've given quite a few talks. And honestly, I still love working on Laravel every single day. I feel just like super lucky that I get to work on this amazing tool with this amazing community. And I'm not burning out on working on Laravel. I'm still honestly as excited as ever to keep working on everything we've built together. So before I keep going, actually, I was backstage and I could not see. Raise your hands again if this was your first Laracon. Wow.
So, okay.
That is crazy. Like the majority of the crowd, it's your first Laracon. Awesome. 2024. It has been a very busy year for us at Laravel. In fact, it's probably marked the biggest shift in the company's history. At the very beginning of this year, Laravel as a company was me and like 9 other people. Now we are a team of over 30 full-time employees. So it has been a rapid change, and honestly, it has been really awesome. We have built an awesome team throughout the beginning of this year, and it's been a privilege to work with all of them. But why did we do this? Why did we hire so many new people? You may have seen our new laravel.com careers page. The reason is because we've been tackling some of the most ambitious and exciting projects that we've ever worked on as a company and that I've ever been involved in. And we had to grow the team to make that happen. So where was Laravel 10 years ago when I first launched Laravel Forge, which was a huge turning point in the company's history, just like this year has been? Laravel Forge was the tool that allowed me to go full-time working on Laravel. So that was a huge shift in the future of Laravel and the future as future of us as a company. Well, as you can see, back in 2014, Laravel was getting just 6,000 Composer installs per day. Not bad, right? And then just 5 years ago in 2019, when we launched Laravel Vapor, Laravel was getting 60,000 Composer installs per day. So where are we today? August 2024. We are now getting a quarter million Composer installs per day on average for the Laravel framework. Pretty mind-blowing. And Laravel's been around a while, right? We're kind of dating ourselves by even giving these figures, you know, all the way back to 2014, which is an eternity in tech web development time. So many things happen, you know, new backend frameworks have come out. Hundreds of new frontend frameworks have come out. And Laravel is still around. And why is Laravel still relevant today? And I believe it's because Laravel is the most productive and enjoyable way to build full-stack web applications without going crazy, to be honest. And I think that's what makes Laravel so special. It includes authentication, authorization, file system abstraction, queuing, payment processor integration, and a wide variety of first-party packages that all work really well together, are really well documented, and just flesh out a really cohesive ecosystem. And what I also like about Laravel is that not only does it bring this enjoyable productivity to the backend, It also brings that same productivity to the frontend. We have awesome frontend options when we're building Laravel apps. Tools like Laravel Livewire, which lets you build modern, reactive, dynamic web applications using just PHP and maybe with a little bit of Alpine.js sprinkled on top. We have Inertia.js. We actually don't hate JavaScript in the PHP world. I know that's surprising to some. We have Inertia, which lets you write a modern Laravel backend and then gracefully pair that with a frontend written in React or Vue using TypeScript. And so you can take advantage of all of the vast, robust libraries available in those ecosystems as well. So where do we go from here? At one of the very first Laracons over 10 years ago, I said that our focus as a company was developer happiness at every step along the application development lifecycle, from local deployment all the way to shipping to production. And that's really what I'm still focused on today, is improving that entire experience. Earlier this year, we launched Laravel Herd for our Windows users. We launched the Mac version last year at Laracon US. And I think this was a huge leap forward in how people develop PHP applications locally. You have one menu bar application you can download, and you have PHP, Composer, even MySQL in a self-contained application, so that when a new developer gets a laptop, they just have one thing to download, and they're ready to build awesome Laravel applications. In a couple weeks, we'll be shipping our Forge integration for Laravel Herd. So this lets you actually link your Forge account to Laravel Herd, see your sites and your sites on your local machine and what they correspond to on Forge, SSH into those sites, edit the environment variables, and more. And this will be coming to Herd in the next couple weeks. We're also going to keep working on the local development story, and it doesn't get much more local than your editor. Many of us that have been doing professional PHP development for a while enjoy robust tools like PhpStorm and the awesome Laravel IDE integration, which gives you powerful IntelliSense for your entire Laravel project. But what about developers that are just coming into the ecosystem? Maybe they just want to try Laravel out, and they've never used professional PHP tooling. One of the most popular free editors for that segment of developers is VS Code. And today I'm happy to announce that we'll be launching our official VS Code extension later this fall. And I think that—
thanks.
Right now, when you download VS Code to build an awesome Laravel experience, you have to also install 5 or 6 other extensions and try to piece together your local development environment. With our new Laravel VS Code extension, you'll have one official extension to have an awesome developer experience on VS Code. And honestly, the best way to see what it looks like is just to show you today. So I'd like to welcome Laravel team member Joe Tannenbaum to the stage to give you a quick demo of our VS Code integration.
What's good? What's up, everybody?
How we doing? Good.
All right.
Okay. Let's get off full screen and back on full screen. Okay, cool. Show of hands, how many people use VS Code here?
Hey, that's what's up.
Okay, cool. How many people use PhpStorm? Great. I know we don't have any NeoVim users here because they would have told us already, so— All right, we are super excited about this VS Code extension. The goal was to reveal as much intelligence about your project as possible, and that manifests itself in 4 different ways: autocomplete, clickable, hover, and diagnostics. Right? So, if we could autocomplete a value, we did. If we could make a value clickable straight to its source, we made it that way. If we could reveal relevant information about that value on hover, we put it there at a glance. And if we knew that you typed an invalid value into your editor, we wanted to warn you right in line. So, let's take a look. Okay. We have the Chirper codebase from the Laravel bootcamp here. In the editor, let's load up the web file. And so here you can see the config helper. And as I start typing, I get autocomplete values, which is pretty cool. So we're going to get the postmark token. Awesome. And as soon as that's in there, it turns into a link. OK, so let's click in and see what happens there. Let's click into that link. Great. It didn't just go to the file. It went to where it's defined in the file. So we're trying to get you where you're going As quickly as possible. Now, you can see we're clearly missing some .env file and .env variables because we have some squiggles here. So we have squiggles here, we have squiggles here, but these ones, they're links, and you can click right into them, and they will go right to where it's defined in the .env. So if you need to edit that value, you can click in and edit it right away. Okay, so we're missing some values. Let's actually fill those values in. If you hover over It'll say— oh, I do not have hover on this mirroring. That's a fun thing. Let's try this again. Whew, big bummer. OK, well— OK, well, don't worry about hover. That's not happening. Let's make sure that's not a full-screen thing. Not hovering. That's awesome. OK, cool. What would happen is, if you hover over it and that value is missing, you get a quick fix, and it'll just say, add it to your .env. And you can click in, it'll add it to your .env, bring you to that .env file, and let you type in the value right away. Uh, furthermore, if we have detected that a value is in your .env.example, we will offer to just copy that value right into your .env file. So that is, uh, that makes things a little bit quicker. Let me see if I hover here. This is just straight up not hovering.
Great.
Hey, no problem. This also works with your vendor files, which is cool. So, if we have the Spatie Laravel Health package installed, you can actually get right in here. Sorry, you have to spell health correctly. That's part of it. And it'll link directly to that file. And on top of which, The hover, if it was— oh, hey, we got a cover. That's great. Okay. Yo, okay, wait.
Hold on.
Hold on.
Let's see if—
let's see if this now works.
Yeah, there we go.
Okay.
Hold on. Let's back up. Hover, quick fix, env.
Great.
We just added it to the env.
Hey.
Okay.
So if we fill that value in, Now it's immediately a link. You see the value right there on hover. And furthermore, if we go back to Postmark, you will actually see that value on hover as well, as well as where that config value— config file is stored. Just to show you, to go back one more, this is a value that we have in our .env.example. And what I was talking about is add value from .env.example, and immediately it just adds it to your .env file, which is pretty cool. So that's config. This is the app binding story. So we have autocomplete for all app binding strings. So as soon as you press the quote, you get autocomplete, and it will click directly into the source where that is actually bound, so you can go right to the code when you need to see it. We also have hover for this, so it will show you this is bound in the cache service provider. And you can— it'll show you exactly where that file is, which is pretty, pretty rad.
Guess what?
Autocomplete for routes. We got 'em. So if we have the password reset route, it becomes a link. You get hover. It'll show you the controller and the method. And when you click into it, it'll bring you directly to that controller and method right away. Okay, not to get too repetitive, but we have autocomplete for translations as well. So if you're localizing your app, Uh, let's look, let's talk about auth throttle. Not only do you have autocomplete for that, you have autocomplete for parameters. So we detect the parameters in the translation string and we'll autocomplete that for you as well. Uh, if you have a lot of translations in your app, such as the Spatie Laravel Health, uh, package, um, we are gonna show you all of the translations that you have on hover, and you can scroll through them right then and there. And if something is wrong or you need to fix something, you can just click directly to that file. It'll bring you directly to that translation to fix it. Next up, we have views. And obviously, you get autocomplete for views. So we are also parsing those view files. And we will— I'm sorry, we're parsing those Blade files. And you get autocomplete for the values that are in that file, the variables that you defined, which is also fun. If you click through, we go straight to that file. And we also have Blade syntax highlighting built into this package. No more extra package to get Blade syntax highlighting. You get it out of the box with the new extension. Uh, all the way— by the way, this is all granularly configurable, so if you decide you actually don't want, say, like, app binding something, you can say, I don't want diagnostics on app binding. I don't want hovering. I don't want linking. You can granularly decide what you want to opt into and opt out of, which is, uh, we wanted to make this as flexible as possible for you. Uh, furthermore, uh, anybody use Inertia in here? We have Inertia people? All right, sweet. Autocomplete for Inertia views. So we get this, and if we're able to parse your props, we will actually autocomplete your props for you as well. Click in straight to that. I, you can see the pattern here. We're trying to like make this as easy as possible. If you change this view and you decide that it's home and not welcome, we will offer to just create that missing Inertia view for you, and it'll just jump right in with a created file cursor in place.
OK.
The star of the show is Eloquent, right. So we put a lot of work into making sure the Eloquent autocomplete story was really robust. In, in your where clauses, you get autocomplete for fields on the model. On top of which, if it's a nested where clause, so if you have a closure, you get autocomplete for the correct model there as well, as well as any chained methods as well.
Cool.
On new model creation, we will autocomplete for you, but only the fillable properties of that model, so we just, like, whittle it down to what's fillable. On relations, we will tell you what relations are available on the model, and we'll autofill that for you. And furthermore, if you need to subquery a relation, we will only offer you the fields on that subquery that are related to the model that you are actually relating. So for example, chirps has messages, but something like, you know, let's say links only has— oop, oop, type Joe. Okay. Uh, like URL, label, order. So it, it is intelligent enough to know what, what relation you're loading in and scope the fields correctly. Uh, okay, let's talk about testing. So we have integrated with VS Code's Test Explorer that's built in. So if we open the Test Explorer, You can see here that we have a familiar directory called tests. And if we drill down into it, you can run your tests directly from this. So you can just press play. They'll run right there. You can jump to a test file. And you'll notice that test files now have these little play buttons next to every single test. You can also run an entire file by clicking the double play button right there. If you need to jump to a specific test, you can. And it will show you failures directly inline. So expect— False to be— to be true. That's going to be— and that's also a syntax error, which is a different thing. We can press play. It'll fail right in line, and it'll give us the error message right then and there. You can also see the full terminal output of the test right here, so you can look at exactly what was run in the terminal. And we can just go ahead and fix that test and rerun it. And it'll turn to green. So this is just a high-level overview of this new VS Code extension, and we are really excited to get this into your hands very, very soon. Thank you so much.
Thank you.
All right. Thanks, Joe. Like Joe said, I think you'll all really dig this extension. We're going to have this out later this fall, so you'll be able to kick the tires and get your hands on it. But I think it's really going to level up the Laravel development experience, especially for newcomers into the ecosystem. So I've had enough slides on my end for a while. It's time to do the old dig into some code, classic Taylor Otwell Laracon keynote style. So we're just going to jump into some cool new open source features that we've been working on over the last few months for the framework. And I'm just going to give a demo of a few of them to you today. So let's jump right in. I've got a little test Laravel application here with a routes file. Let me make this a little bit bigger for you. And yeah, let's jump into the first feature. So you can see here in this route, I'm using Laravel's storage facade to generate a temporary URL to a file that I actually have on DigitalOcean Spaces. Which is an S3-compatible cloud storage system. So Laravel Storage facade is really cool in that it lets you work with the same API across a variety of file storage backends. That could be local storage, it could be Amazon S3 or Cloudflare R2, or like in this case, DigitalOcean Spaces. But you get to use the same methods and API across all of those file systems, which is super convenient because it means you can change file systems at any time really and not have to update your code that much. So anyway, I'm generating a temporary URL. And what that means is this is going to generate a URL to this file, but it's only going to be valid for 5 seconds. So this is a very common use case, or a very common thing to do if you have a temporary file download that you want to offer to your customer. You don't want other users to be able to access this file, so you time limit how long the link is valid. So super common for— secure file downloads. Okay. So if we hit this route, we get a URL, and we click it, and we get this wallpaper. And you can see, like, if I refresh the page, it's already expired, and we can no longer access the file. Great. So that's all working as intended. This has been in Laravel for quite a while, actually. But what happens if we actually go back to our application, and let's dig into our environment file. And let's change the driver to local for, like, the local file system. And now if I hit the route, you'll see I get internal server error. This driver does not support creating temporary URLs. And this has been a huge bummer in the past because if you're developing locally and your application uses temporary URLs, you had to actually go out to, like, S3 or to Cloudflare, make a bucket or make a space, add the key to your local development machine, and you're like actually calling out to the cloud to interact with these buckets. And that's just kind of a bummer because if you're working locally, you just kind of want everything in your local file system. It's faster. You don't have really these external dependencies. It's just a much better way to work. So this has always been a big pain point until now. So we're gonna be soon launching the ability to enable private local file serving directly from your Laravel application. So how does it work? And thankfully it's really simple. You just go into your config file systems file. I go down here to the disk and there's a new serve option. So I'm going to switch that to true. And if we open up like the file tree over here on the side and we go into storage, you can see there's an app private directory where I have that wallpaper that we just accessed on DigitalOcean Spaces. So it's basically the same file, but just on my local disk.
disk.
So if we hit this route now, we actually get a URL, and it's using our local application. And this is using Laravel signed URLs with expiration timestamps. So if I try to hit the route again, you can see we get 403 Forbidden. So we're bringing really easy temporary URLs to the local file system. This is awesome for local development, but you could even ship this to production if you have a fairly light load production application, and you just want to use local file storage on your production server, you can totally use this, totally production ready and secure. So that's local private files coming very soon.
All right.
Let's keep moving. Let's jump into another feature. This is a cool one. So we call this container attributes. So you can see I've got this route here, and we're injecting an action into it. Maybe it's deploy application. I'm going to pop open that class. And maybe we want to inject a value here that's a string. And maybe it comes from our config files. So we might do something like string GitHub token, let's say. And we'll dump out the value here. Now, if I hit this route, the deploy route, you can see that I get an error that there was an unresolvable dependency on this parameter. And that makes sense because Laravel doesn't know what string you want to inject into this class. You just said you wanted a string, and Laravel's like, okay, what string do you want? You know, I don't know what to give you here. And so previously, like, if we wanted to pull this from the config file and inject it into this class, we would have to do something like this. We would have to go to maybe like our AppServiceProvider, and we would have to do kind of like this whole song and dance. Where we say, when deploy application needs GitHub token, give this value from the config files. And hopefully if this works, this should actually give us a value that we can dump out. Okay, and it does. All right, so we see my GitHub token, which is the value that I have in my config files. But it's kind of a pain to have to go to your app service provider, you know, just to do something relatively simple like that, to pull a value from your config. But with container attributes, you don't have to do that anymore. You can actually put that information right in the constructor of your class. So let's go back and just get rid of this again. We'll comment that out. And we'll come back here to our deploy action constructor. And now we can use container attributes and just say config.services.GITHUB_TOKEN, just like that. And we'll import that attribute. And now we should just be able to hit this route. And we get the token. So we can pull it right out of the config file using the built-in container attributes. And we have a few other—
thanks.
And config is not the only container attribute we've built into the framework. We've actually built 7 or 8 of these attributes for common use cases. So another one might be injecting a specific database connection into the class with the DB attribute. We can inject a specific connection, maybe the SQLite connection. I'm going to import that attribute. I'm going to import database connection. And let's just go ahead and dump that out and see what we get.
All right.
We hit this. OK. We get a SQLite connection. Great. That's what we expect. And we can just super easily come in here and tweak this. So, like, we could say MySQL, and we get a MySQL connection.
Cool.
So this might be useful if you have 2 separate databases for your app. Maybe one stores, like, analytics and metrics about the app, and one's your primary database. And you have a class where you want to inject your analytical database into the class. It's very easy just to do that using container attributes now instead of having to do contextual binding in your service providers. We've done some other cool ones. But before I show you this next one, let me go ahead and make sure I'm logged into this app. OK, so I'm going to go to the dashboard. I'm logged in. Great. That all looks good. We even have an attribute to inject the currently authenticated user. So I can just say current_user, user. We'll import that model. We'll import that attribute. And let's just dump out the user_to_array.
All right.
So we'll go back to that deploy route. And you can see we get the currently authenticated user injected directly into the class. Super easy, super convenient. All right, so we've— that's 3 of the built-in attributes. We've actually written a few more. So we have attributes for injecting different file system disk, different log channels, basically anything that has a driver in Laravel or multiple instances, you can use container attributes to inject the right instance that you want. And you can even create your own custom attributes just by implementing a simple interface. So you can build all sorts of creative custom container attributes for your app. or for your package and ship them out to your users. All right. So that's container attributes. Let's dig into a new Eloquent feature. Eloquent, obviously very popular feature of Laravel. It's really, I think, my favorite feature of Laravel. But let's look at something with this route. So in this route, you can see that I'm pulling users with their blog posts, let's say. And let's go ahead and just hit this and see what we get. You can see that I've got 2 users, so there's me, and I've got 3 blog posts right here in this JSON structure. And then we've got Jess Archer, a second user, and she also has 3 blog posts. So 2 users, 3 blog posts apiece. Now, so what people will do is, you know, like, they'll retrieve the users, and they'll start looping through them like this, users as user, and then maybe they, like, loop into the posts for each user. And then here's where it gets a little gnarly. A lot of people want to try to do something like this. They'll go from the post back to the user, so like the parent user that owns the posts, and they'll access some data on that user. So let's hit the route now. OK. We get what we would expect. We get my email address 3 times. We get Jess's 3 times. So, you know—
That's right.
6 total blog posts, 6 total email addresses as we loop through the post. But let's see what database queries are happening. So I'm going to uncomment this db.listen. OK, so now we're seeing the database queries. And you can see that we've got like an n+1 query problem going on. So after each email address, you're seeing how it's making a query to the users table every time we spin through the post. So for each post, it's going back to the user table, doing a query, pulling the user, Not good, right? This is a performance problem at scale. So how can we fix this? What if we want the parent user to be hydrated on the posts so they all share the same user instance, and if I update the user on the post, it's synchronized across all the posts? It's pretty tricky. People actually write some pretty gnarly code to make this happen right now. They'll do something like this. They'll say, like, users.each set relation— or, yeah, users.each Function user, user.post.each, set relation, user, user. I hope this works. This is— OK. We resolved the N+1 query problem, but we had to write some absolutely atrocious code to make that happen. And not only is it, like, ugly code, it actually would create an infinite loop if you tried to return those users from the route, because The users have the posts, which have the users, which have the posts, you know, which have the users. So it's just an infinite recursion, and the app would just hang. It would actually— wouldn't return anything at all. So we're fixing that. We're making that much easier. So let's get rid of this gnarly code. Okay? Now we're back to our n+1 problem. What if there was a much easier way to solve this problem? It kind of feels like there should be. This feels like overly complex for such a simple use case. Well, now you can just come into the user model and say you want these posts to be chaperoned. And that's all you have to do. And it will hydrate the correct user onto the post. The posts will all be synchronized to their user. You don't— we actually prevent the infinite recursion now. So if you try to return this from the route, everything works really well. It works how you would expect. So much, much easier. And so you can chaperone these models in 2 ways. You can define it right on the relation like I did here, but you can also opt into it at runtime. So when I make this post query, let's do something like this. When I eager load these posts, I could actually, like, get the query here, and say post.chaperone. So maybe you don't want it to happen every time you load that relation, only sometimes. You could opt into it at runtime like this. So now if we hit this route, you know, we still see we've eliminated our N+1 query problem. And vice versa, like, if we define it on the relation, OK, so we chaperone there. We can actually opt out. So we could say, like, without chaperone. And now we, like, reintroduced the N+1 query problem. But sometimes you might want to do that if it's a small dataset and you want each post to have, like, a fresh instance of the user. So you can choose how you interact with this feature, but much, much easier to accomplish this use case without hanging your entire app or running out of memory or writing some really atrocious code. So that is chaperoned Eloquent models.
Thank you.
All right, let's dig into the next feature. This next feature is the brainchild of Laravel team member Tim McDonald, who is down in Australia. Shout out to Tim. He comes up with some awesome ideas, so I'm happy to demo this on his behalf. But this was his brainchild, and I really dig it, and I hope you do too as well. So we have this route, route defer. You can see we're calling this method metrics report. Let's pretend this does some really slow stuff. Maybe it calls out to an API, it works with some external services, In our app, just to, like, simulate that work, we're going to sleep for 1 second, and then we'll just return a random currency value, just to simulate some sort of slow API that we need to interact with. And then we'll log the value out to our logs and return it. So let's go ahead and hit this route. You can see it took a while, okay? It took a little bit over a second, which is to be expected, because we slept for a second. Now, if you wanted to make this faster or you wanted to do this in the background because maybe the user— we're not even using this for the user. We're not showing it on the screen. We just need to do it. Maybe we need to report some sort of metrics to some external service, but really the user doesn't really care about any of that or need to worry about that. And it's kind of a bummer because our whole app feels slow for this thing that the user doesn't even see or care about. And previously, if we wanted to fix this, we'd have to write a queue job. We'd have to spin up queue workers. We'd have to make sure supervisor is keeping the queued workers running. There's a lot of legwork, you know, just to do something relatively simple like move this to the background. So today, we're introducing a new way to push work to the background without setting up any queues, without running any persistent processes, and it's super simple. I'll show you how it works. We'll just come to this line, and we'll say defer.
All right.
Let's move this over here. Let's pull up our logs. I'm going to start up this. 26 milliseconds. And you can see that we deferred the reporting of that metric to the background. And we can just keep hitting this route. We have no queue workers running. We have no persistent processes consuming queue jobs. All we have to do is wrap a piece of code in the defer function.
All right.
And it will be pushed to the background to be executed after the response is already sent to the browser. And this works because PHP-FPM and modern PHP application servers like FrankenPHP let us do work after the response has been sent to the user. We don't actually have to run a queue or anything like that to just simply push a function to the background. So this is all you have to do to defer something to the background, and everything will just work without any other queue processes.
Now—
What if something goes wrong after we defer a function? So maybe we're deferring, like, the sending of a welcome email to the users that just signed up for our app. What if something goes wrong after that? So let me show you what happens. Let's just throw a new exception here. Something Wow, something went wrong. My typing went wrong. All right, so we've got this exception here, and let's go ahead and hit the route again. Okay, so something went wrong. We see that over on the right side, you can see the exception, but we never got the deferred metric call. It was canceled. So if an exception happens after you defer a function, the default behavior is we'll just discard the deferred function. I think this is a sensible default behavior, because if you're doing something like queuing a welcome email or deferring a welcome email, and something goes wrong, you don't want to send the email because the user may not even be in the system if something went wrong. But sometimes you may want the deferred function to run even if an exception happens. So we can actually just chain on a simple method, always. And if we chain always onto defer, the deferred function is always executed. It does not matter what happens in your application after this function is deferred. It's going to run no matter what. So, now, if we hit the route again, we see the error, but we also see the deferred function executed later. So, sometimes you might want that to happen. If you're reporting metrics to an external service, you may want to report those metrics even if the request fails or, or whatever. So, the always method lets you make that happen. All right, and what's really cool about defer is it's not limited to just web requests. So, you can actually use defer in queued jobs and artisan commands and get the same behavior, the same consis— consistency behavior throughout your application stack. So if I go out to this process podcast job, you can see I'm deferring a call to the metrics method, and then I'm logging that we're handling the job.
All right.
So let's come out here. Let's start a queue worker. And let's— do I have a route for this? Let's dispatch it here. We'll just get rid of that.
this.
ProcessPodcastDispatch. All right. I'll import that class. All right. So now if I hit this, okay, we see handling_job, and then we see the deferred_function. Even though deferred_function was registered before we logged handling_job, you can see that it obviously logged after because it was deferred. And the same behavior with exceptions applies to queued jobs. So if an exception were to happen in this queued job after we deferred the function, it would be canceled just like on a web request unless you chain always onto the deferred function call. So, you can use defer anywhere without really having to think about where you are. Are you on the CLI? Are you on the queue? Are you on the web request? You can just always use defer. You have nice consistent behavior, and things will just be pushed to the background with no queue workers necessary. So, that's deferred functions. Really awesome for just pushing simple tasks to the background. Really lightweight, really quick. No extra workers needed.
All right.
Let me adjust my screen a little bit here. So defer is really cool on its own, but we thought there were some other interesting ways we could use deferred functions in Laravel itself. And one of those ways is a new method in the cache. But before I show you that, let me show you an existing method, cache remember. So you can see in this cache route, I'm calling cache remember, and I'm specifying the key as metrics. We're caching them, caching these metrics for 5 seconds. We're just gonna get 3 metrics from our service. Again, it's gonna sleep for a second each time it pulls a metric, and then we're gonna return that cache value. So we would expect this first page hit to kind of take a while. Let's just see what happens. We hit cache. It's spinning. You can see this took 3 seconds, so pretty slow. If we hit the route again, it's pretty fast because we cached it for 5 seconds. But now it's, like, recalculating again. So now we're getting another slow request, and then we're fast again. And this is OK. It's not super ideal.
Why?
Because a lot of users are gonna hit these slow requests. Someone's got to be the unlucky user that hits the app when your cache is expired, and they have to sit there for 3 seconds while everything recalculates, and that's kind of a bummer. Um, so we're fixing that. So we're introducing a new cache method called cacheFlexible. And when you do cacheFlexible, you actually pass 2 values. And this is pretty sweet, so I'll explain both values. So the first value, 5 seconds, If someone tries to access the cached value before 5 seconds, we just immediately serve the cached value. You know, it's still fresh. The data is still good. If someone requests it after 10 seconds, so after the second value, we unfortunately have to recalculate the cache. We consider the data is too old. We can't show it to the user because it's just been too long. It's totally stale. So we have to recalculate it, and the user probably will get a slow request. But the real magic happens in between the 2 numbers. Let's just go ahead and hit the route, and let's just look at the behavior, and then we'll talk about what happens between the two. All right, so we're going to hit the cached route. We're going to get a slow request because we've got to hydrate the cache. OK, there it was slow. OK, now we're fast. So let's keep an eye on the time and on the numbers. You can see the numbers updated, but we were still fast. And if I keep hitting the route, we're still really fast.
OK.
Let's see if they'll update again. They updated again. We're still fast. So no one's hitting slow requests, even though the data's got to be recalculating somehow. And let's dig into how this works. So if a user hits the route in between the 2 values— say they hit it 7 seconds after we cached— we actually serve them the cached data, because we still consider it pretty good. But we defer a function to recalculate the cache in the background. using defer. So it's basically an implementation of the stay a while revalidate pattern, if you've ever heard of that. And you don't have to set up any queue workers. You don't have to set up any background processes. It's just an awesome fast experience for all of your users just by you, you using cache flexible and the power of deferred functions in Laravel. Really cool. All right, I'm super pumped about this feature. I think I'm gonna use this quite a bit, actually. Let's keep moving. We've got this concurrency route. This is a slow one. So, in this route, we're doing a lot of work. You can see we're calling metrics 5 times. It takes a second each time, so that's gonna be at least 5 seconds we've racked up on the response time. And a lot of times, you need to do slow work that isn't necessarily related to each other, or needs to happen in any certain order, Like, maybe you need to call a couple different APIs or even need to make a couple database queries, but it doesn't really matter what order they happen, and they don't really need to care about each other. So usually you end up just doing them synchronously, all in like top-down order like I have here. And if we hit this route, we can see this one's going to spin for a while.
Come on.
All right. So we finally made it. 5 seconds, not good, right? We can't ship this to users. But since all these methods are unrelated, it would be awesome if we could just do them at the same time. And so now you can. We're introducing a new concurrency facade right into Laravel. So let's just see what it looks like. I can say values concurrency run. I'll pass in an array of things I want to be concurrent. We'll say metrics, GET. We'll do it 5 times. Let's just kind of get rid of this.
All right.
Let's make sure we got the concurrency facade imported. And let's hit the route now.
All right.
It only took 1 second, because we're doing all of the metrics gathering at the same time. And what's happening is the concurrency facade is fanning out this work to other PHP processes in the background, and then gathering up the results and giving them back to you all in one array. But all of the work was done simultaneously. So we can simultaneously run all of this expensive work at the same time and get all of the results. And what's cool is it really doesn't matter, even if we're gathering more metrics here, our response time is basically going to stay the same because we're running it all concurrently. So we still just took a little over a second, even though it really would have been over 10 seconds if it was run in order from top down. All right, so that's the concurrency. facade. Really simple way just to fan out work across PHP processes, especially unrelated work that you can just run simultaneously. Super easy to use.
All right.
Let's go down to another concurrency route. Concurrency 2. Sometimes you have work that is sort of unrelated, like I said, and not only is it unrelated, you actually just don't care about the results of the work at all. So, this is, again, super common. You're making some API call to report some data. You actually are not expecting any sort of helpful response from the service, just like a 200 OK, we got your data. Maybe you're doing that with a few different services, and you're just not gonna use these results, again, to show anything helpful to the user, but they need to happen. It would be awesome if we could do all of that concurrently, but our users didn't have to wait. So, like, right now, if I hit this route, you can see it ran in 1 second. That's, like, it's slow, right? We, like, that's not ideal. But the work is slow. But since the user doesn't need it, let's just do concurrency defer. Now we're down to 29 milliseconds. And all of that work is still being deferred to the background, and it's being fanned out to run concurrently across multiple PHP processes. So you could take advantage of both concurrency and deferring concurrent functions simultaneously. It's really super slick. And since we're using defer under the hood, a lot of the same rules applies when you're using the defer function, so it's super consistent. So if an exception happens down here, let's say something went wrong, all of that deferred work will be canceled, and we'll just discard it. But again, if you want it to run, you can just say always, and it will always run that concurrent work and defer it to the background. It's super consistent, super easy to use. All right, so that's an overview of the concurrency facade in Laravel, and it's an overview of a few of the new features we've been working on Laravel, and we plan to ship all of these features in beta next week so that you can start playing with them immediately.
Thank you. All right. Whew.
Let's change gears a bit. We've talked a lot about Laravel, the framework, a lot of kind of backendy type stuff. Let's change gears to the frontend.
Woo!
Like I said, Laravel has awesome frontend options, right? We have Laravel Livewire, which is like mind-blowing. Like when I first saw Laravel Livewire in 2019, I was like, my face like melted off my body. I was just like so mind-blown. that this was even possible. And, like, I mean, we can pull up this Livewire route, right. Let's go to /votes. And let me pull up this example. Like, if you showed me this code on the left 10 years ago at Laracon 2014 and said I could have this, like, real-time dynamic component on the frontend that's persisting state using just PHP that looks like the stuff on the left, I would have, like, I would have not understood how that was even possible or what the path to achieving that kind of functionality was in PHP. So shout out to Caleb, wherever he is, on truly blowing our minds with Livewire. But I don't want to spend too much time on Livewire, not because I don't love Livewire, but because Caleb talks in the morning, and I don't want to spoil his fun or give anything away. about what he's been working on. But tomorrow I know, because I've seen a preview of the stuff he's been working on, and it's going to be really awesome. It's going to take your Laravel Livewire experience to the next level, I think. And I think it's really been like the missing piece that Livewire has needed for a while. So I'm excited for him to show it to you in the morning. And we'll talk about that tomorrow. So I'm going to talk about the other half of the Laravel frontend story, which is Inertia. How many of you use Inertia?
Woo! Woo! Woo!
Okay, good. Fair, a fair number of you, which is good. Uh, you're in the right place. Um, Laravel Inertia is a way to pair your Laravel backend with a modern React or Vue frontend. And it can be written in JavaScript, it can be written in TypeScript. You can even use Svelte, uh, with Inertia. And Inertia is really like this sort of connecting mechanism between your backend and your frontend. So you have routes and controllers in your Laravel app just like normal, but instead of returning a Blade view, we return like a React page or a Vue page. And the array you pass to that page on your backend gets hydrated into the props of that page on your frontend. So the benefit of that is you get to enjoy all of the like Laravel server-side routing, data hydration, all of that good stuff, but you get to use a vast frontend ecosystem from React or Vue. So you get to tap into things like, uh, Tailwind's Catalyst UI components to build really awesome frontends using their components. You can tap into things like Framer Motion in React to build really great animation experiences on your apps, but you don't have to leave your Laravel backend behind. And it all just like fits together like a glove and feels really cohesive and really nice. Um, so in many ways I've always said that I don't think of Inertia as a frontend framework in the same way that, like, React or Vue or even Livewire is a frontend framework. It's really like this translation layer between your backend and your frontend, which is written in React. And React is your frontend, or Vue. And because of that, I've always said, like, I feel like Inertia is just, like, kind of done. Like, it's kind of finished software, you know? Like, some software is just complete. And it works, and it does what we need, And there's just not a lot of other stuff to do. But I think I was wrong about that.
Yes.
I don't think Inertia is done. Inertia 1.0 is great, but there— we actually discovered there's a lot more cool stuff we could do. So today I'm gonna walk you through Inertia 2.0, and I'm super pumped to give you the first public unveil of some of the stuff we've been working on. All right. So we've actually got a playground here for Inertia. So let's pull it up. And I'm going to walk you through— you weren't supposed to— do not pretend you did not see that. Wipe that from your brain. OK. It's gone. I'm going to walk you through not 1, not 2, not 3, but as you can see, 6 new features coming to Inertia 2. And I think they're really slick. Uh, Joe Tanenbaum and Jonathan Rinnig, the creator of Inertia, have really like knocked it out of the park working on these features. And I'm gonna give you a quick walkthrough of some of them, but they're really pretty sweet.
Okay.
The first one, you're gonna think this is boring, but it's really like the foundational piece to the rest of all of these features. And we call it async requests. And I've gotta nerd out with you for a second on how Inertia works to help you realize why this is good. Right now in Inertia 1, every request is synchronous, and no request can be happening at the same time as another request. And if you try to make another request while a request is happening, it's canceled. And in many ways, that is good, because it's sort of how traditional web applications work, right? You click on a link, you wait, you see the page.
You—
You do something, you wait for the response. That's kind of how the web worked a long time ago, right, when we used to build basic web applications. But it can lead to some really unexpected behaviors if you're using inertia. So if you're using inertia to, say, reload some data on an interval, like maybe you're on a page and you're reloading some data every second, and let's say the user clicks on a link, and before the link can load the page, your reload fires, it actually cancels the link click that the user just made. And I think many people are not aware of this behavior of Inertia, um, and it can cause sort of subtle bugs in your application. So we're fixing that. And we foundationally rewrote the whole request routing layer of Inertia to make this happen. So in Inertia 2.0, all reload requests are async by default. They happen in the background and they do not cancel other requests and they do not show progress indicators. Nerd, boring, boo, what does that mean? Okay, the first thing it means is, like, on this links tab, I've got these toggle buttons, and I can toggle these really quickly, and I get, like, this nice optimistic UI feeling experience, and it doesn't really matter how fast I toggle them. None of the requests are stepping on the other requests or cancelling other requests. It just all works pretty much how you would expect. And the way you tap into this in the code is you just throw this little async modifier on any link in Inertia. And that says that request should be in the background and should not affect, you know, any other requests, and other requests should not affect it. All right, so that's async requests in Inertia 2.0, and I needed to preface with this because it really unlocks a lot of other cool features that I'm about to show you. So tapping into the power of async requests, we can really enable the next 5 things. Um, and the next thing we're bringing to Inertia 2.0 is an easy way to poll your data on a page. So let's go ahead and hit this automatic tab, and you can see I've got this, like, leaderboard of scores, and you can see the scores updating automatically as that polling is happening. Pretty simple concept, right? You can get pretty far with polling, actually, before you have to reach for WebSockets when you're building a web application. So how do you use this new feature in Inertia? It's super simple. You just say usePoll. And you give it your time interval and what data you want to update, and Inertia will take care of the rest. It will start polling when the page mounts, and it will stop polling when the page unmounts. And if the user changes tabs, the polling will automatically throttle, so you're not just wasting bandwidth. All right. Keep losing my screen. Um, so that is automatic polling. You can also do manual polling. So sometimes you want to be able to control when the polling starts or stops. So in this example, you can see I have a start button. So if I hit start, we start polling on the page. If I hit stop, we stop polling. The way that works is when you call usePoll, you can actually get stop and start callbacks. That way, if you want to manually control the polling behavior, it's super simple. So for example, we might do this on Laravel Forge when a deployment starts. We want to start polling for deployment output. When a deployment's over, we want to stop polling for deployment output. We don't really need to be polling the whole time you're on the page. All right, so it's super simple just to start, stop, control polling. Everything works. Just use usePoll in Inertia 2.0. All right, so that's easy polling helpers in Inertia. Next feature async request unlocks is what we call whenVisible. whenVisible is a convenient wrapper around the intersection observer API that lets you easily trigger prop loading when a component comes onto screen, when it scrolls into view on the page. That was kind of a mouthful. So what does that mean? So let's go to the demo. As I scroll down this page, you can see that I'm hitting a component, and it's loading in when it comes available— when it becomes viewable on the screen. So we keep scrolling down the page. Boom. That one loads in. That one loads in. This is awesome if you have something way down the page that maybe does an expensive Eloquent query to load some big table of data, you don't really need to do that on initial page load. Like, why not just wait until maybe the user doesn't even scroll to that? Wait till they scroll to that table, and then we can load in all of the data, and it makes the page much faster. You get much, like, swifter response times for your users. What does that look like to use? So on the server side, we use an optional prop. This existed in Inertia 1.0. We're just saying, On the initial page load, you don't really need to calculate this prop. You don't need to run this query. All right? And then on the client side—
Work.
That made it worse. Who said that? Okay. The screen's been working hard today, I guess. Getting tired. Okay. So server-side, Inertia optional. On the client side, we can use Inertia's new whenVisible component. So we ship this with Inertia. And we can say when this piece of the page becomes visible, go asynchronously fetch this prop or this set of props. And you can see we can even have a fallback template for our loading states. And then when that data is loaded in, it will render the template that we pass into this component. Like I said, we can even wait for multiple pieces of data. So maybe when this becomes visible on the screen, we want to go get the users and the teams asynchronously. We can have loading states, and then the data will show on the page when it's ready. And we can even use any of Inertia's request parameters to say have finish or lifecycle hooks if we want to tap into the request lifecycle of the whenVisible component. So it's super flexible, super easy to use, and it will vastly speed up your applications for your users. All right, so that's the basic usage of the whenVisible component. We can get a little bit more advanced. What if we actually want to have a buffer? So we want to say when a component is within 200 pixels of coming on the screen, we want to start loading the data. So we want to start a little bit early so that it's ready by the time the user gets down to that section of the screen. So that's what the code looks like. We just pass a buffer prop. And now as I scroll down the page, you can see I hit these orange arrows, and that's the threshold of the buffer. And you can see the data's already loaded in. So boom, I hit the threshold, data's loaded in. So as we scroll down the page, You know, you get a seamless experience where the data is just always available, and it's super easy to tap into, and again, will make your pages much, much faster. So that is Inertia when visible and Inertia 2.0. I think it's pretty sweet.
All right.
We can actually use when visible to build something else on top of this sort of like lower-level component. And we can use it to build really easy infinite scrolling experiences in Inertia. Doing infinite scrolling in Inertia 1.0 is doable. It is probably not enjoyable or fun, um, but we're trying to make it that way. So we can tap into when visible, and as I scroll down this page of pictures, you can see that we just get more pictures and I can keep scrolling forever. All right, you've probably seen applications that work like this. What does this look like? How does it work on the code side? On the backend, we have a new feature in Inertia 2.0 called mergeable props. And what this means is when I say Inertia merge and pass it some data, any other subsequent request to get that prop will append the new data onto the data it previously retrieved on the client side. So basically I can keep returning images and it will keep appending to the prop it already received. received on the first page load. And then on the client side, I can just tap into whenVisible. I don't really need a new component here, but I just put a whenVisible at the bottom of my image list. I can hook into the request parameters to increment the page. I can say that I only want this data reloaded, and I want to preserve the URL, because as we scroll, we don't really want the URL changing, right? This is like just one infinitely scrolling page. So it's that simple to build infinite scrolling experiences in Inertia On Inertia 2.0. Really cool. I'm actually going to back up here. I showed you the Vue example for whenVisible, but for you React users, you actually just use the Suspense API to tap into whenVisible. So we have Suspense, and you can use the useWhenVisible hook to build these same types of experiences in React. So this has both Vue and React support. All right. Let's hop into the next feature, one of my favorites, inertia page prefetching. I'm very excited about this feature. All right. So let's hit the non-prefetch tab. If we hit these different authors, we'll see the standard inertia behavior. So, like, as I click each author, you can see the progress bar come across the top, and we kind of have to wait for a second for the page to load. Again, like, that's, like, sort of fine, right? It's not bad, but sometimes you want to prefetch that stuff. So we're letting you do that now really easily. So let's hit the prefetch tab. And there's a couple of different ways you can do prefetching. The default way is on hover. So if I hover over here, then I click, I get the page instantly, because as soon as I started hovering, Inertia fetched the page and cached it just to be ready in case the user clicked that link. So it loaded almost instantaneously. This makes a huge difference in your apps. We're already using this in some of the stuff we're building, and you can, like, seriously feel the difference in the speed of the app when you start adding this to your application. If you want to be super aggressive, you could even prefetch when the page mounts. So if you feel, I guess, extremely confident that the user is going to click this, you can go ahead and prefetch that page as soon as the original page loads, and it will just be instantly ready.
All right, great.
But how do you use it? So let's look at the code. Really easy. On any link tag, just throw prefetch on that thing, and you will have prefetch-on-hover behavior. By default, we cache that response for 30 seconds, and then we just sort of discard it because we consider it stale. But as you can see down below, you can customize that cache duration. So you could make it longer. You could make it shorter based on kind of what you're feeling for your particular app or your particular data. And if you want to do prefetch onMount, here's what that looks like. So you can just say prefetch and then pass it mount. And look at this bottom one. This is an interesting one. So you can actually pass 2 values to the cacheFor prop. And that might look familiar. It might look a lot like the cacheFlexible method that we saw earlier. So what does this do? And I think it's easier to show you rather than to explain it. So let's hit the stale-while-revalidate tab. And this has 2 tabs within it, Laravel and Tailwind. They're prefetched on mount. Watch what happens when I switch back to Laravel after 5 seconds. See how the data's gracefully updating after I hit the page? The page is loading instantly, but then the data is gracefully updating. So what is happening is when you have a prefetch and you have a cache full with 2 values, if we click on the prefetch page, in between the 2 values, it will serve the cached page immediately from the cache and then gracefully reload the data in the background so that you can provide this seamless transition for users that just refreshes as soon as they get there. And this doesn't work for all screens, but when it works, it, like, really works. And so things like charts and graphs and things, it's usually fine if you just show the data immediately and then the graph just kind of, like, do you— like, adjust to the current time. It almost, like, looks cool, you know what I mean? So really powerful feature in prefetch to let you implement that same stale-while-revalidate pattern on your frontend. All right, so that is Inertia prefetching. Will seriously speed up your apps. Okay, I want to dig into one more feature of Inertia 2.0. And that is deferred props. It's another one near and dear to my heart. All right, so we have this non-deferred tab, and if I hit this tab, you can see again the typical inertia behavior where we sort of wait for the whole page to be ready, and then we show the page. Again, not bad, I guess. We had no loading states. Everything just sort of loaded. It felt like a traditional old-school web application. But sometimes it would be really great if you could just show the page really quick and then load the data in after. So we're making that super easy in Inertia 2.0. So if I hit this deferred tab, you can see, boom, we're on the page, we have loading states, and then the data pops in when it's ready. Okay? Really great. How do you use it? On the backend, you can just say inertia defer for a prop, and that will make that a deferred prop. And then on the frontend, you can use our new built-in deferred component to specify your loading state and then what should render when the data is ready. And you can see that you can even wait for multiple pieces of data. So you can say this piece of the page, we're waiting on the deferred data user count and order count. We can give it a loading state, and then we can show the data when it's available. Now you can see— well, before I move on, let me show you the React. So again, we tap into Suspense, and we use the new useDeferred hook, and we can tap into all of the same deferred prop features as on the Vue side. Let me close the code and reload the page again. You can see how all the deferred data popped in at the same time. So the stats across the top popped in at the same time as the user table across the bottom. So the default behavior is when you have deferred props, Inertia will go out to the server, gather up all the deferred props in the background, send them all down to the client at the same time. Sometimes that's fine, but sometimes you might want to group the data into certain deferred groups. So let's hit this other tab. You can see that we get the table, and then we get the stats when it's ready. So Inertia 2.0 lets you assign keys to your deferred props so that you can group them. So maybe you have some stuff that takes a lot longer than the other stuff. Put that in its own group, and then the other deferred props don't have to wait on the really slow one. They can just render as soon as they're ready. And it's all super easy to use, easy to declare loading states. It all just works. So that's Inertia deferred props in Inertia 2.0. So that's a preview of Inertia 2: async requests, polling, when visible, infinite scrolling, prefetching, and deferred props with Vue and React support for every feature. Again, I want to thank Joe Tannenbaum and Jonathan Rennig for absolutely knocking this thing out of the park. I think it's going to be an awesome breath of fresh air for Inertia users. And we hope to have Inertia 2 in your hands in early October. Not that far away, by the way. Okay, we're getting into September. So pretty soon you'll have Inertia 2.0 in your hands and you can use all of these great features. All right, so that's Inertia 2.0. and a round of framework updates from the Laravel team. So I'm super excited for the future of Laravel. And frontend and design has always been super important for Laravel, both on the code side and, like, in the true design sense of the word on the frontend. For code, designing really expressive, enjoyable APIs has always been, like, super— a super big passion of mine. I want the code to feel really enjoyable to write, really memorable. It's just fun to code in Laravel. And when we build products, we want the design to feel really great, to feel really polished, to feel really thought through. And as part of scaling Laravel this year, I've been super pumped to bring on a new head of design. And I'd like to invite him on stage just to share a few words with you about how we're thinking about design going forward at Laravel. So I'd like to wake— welcome David Hill to the stage.
Everybody get up, it's time to slam now. We got a real jam going down. Welcome to the Space Jam. Space Jam. Here's your chance, do your dance at the Space Jam.
Hi.
Okay. Hey, everyone. This is exciting. My name is David Hill. I'm head of design at Laravel. I'm super excited to be here today. When Taylor asked if I wanted to say a few words, my immediate response was, I'd love to. But first, before we jump in, just a couple of important house rules. They're really simple. The first rule of Laravel Design Club is we do not say the word pretty. Florian, you and I, we can have words later. The second rule of L'Oréal Design Club is— We do not say the word pretty. We do not say the word pretty. Design is so much more than the way things look. Design is way things work. It's problem-solving at every level of an experience. It's what makes a brand feel like a brand. It's the attention to detail you give something when you think people couldn't possibly notice, because I can promise you people will notice whether they know it consciously or not. It's the hundreds and thousands of tiny details that don't matter individually that collectively compound over time to create something that does matter. And, well, just ask Jason Beggs. Hey, Jason, can we take the padding on this icon and change it from 8 pixels to 4? Or for those of you who only speak Tailwind, p-2 to p-1. Hey, Jason, that icon, can we make the SVG animated to give it a sense of motion? Or, hey Jason, that animation, can you tweak the transition to make it feel swish, like my jump shot? Because design matters, and design is a differentiator. And great design? Well, great design requires more than just design. Great design requires time, because our first ideas are rarely our best ideas. More often than not, they're just the obvious ones, the ones we need to push past in order to get to the good stuff. And great design requires teamwork and collaboration across all levels of an organization. It can't just be the final step of styling something. Great design requires empathy and humility, and as with anything done well, requires extraordinary amounts of effort. Now, Laravel has always done a great job of design. It's what drew me to the framework back in 2019 when I started to use it. And yes, designers should code. I'm just putting it out there. But a big focus of my role is to continue that great work, and with the help of everyone at Laravel and the community, to push the design of our products and experiences forward. To make them even better. Now, outside of all the great product work that we've been busy cooking, and we've been busy, there are 3 upcoming projects that I'd like to share with you today. The first is a Laravel brand site. For those of you that work with Laravel brand, we'll be introducing a site where you can download templates and resources to help you and to help maintain brand consistency. The second, which I'm really excited about, is a complete refresh of laravel.com. Not only will we add value and explain the value that we add, we'll also introduce a sense of artistry, poetry, elegance, all the values that we try to embed in the framework itself. And third, let's not forget the Laravel docs. Laravel documentation is world-class. It's one of, if not the best documentation sites out there. But we think we can make it better, and we need your help. So whether you're a junior developer making your very first Laravel application, or you're a gnarly seasoned pro who's been using the framework since v1.0, we need to hear from you. We'd love to hear your thoughts, feedback, ideas, and suggestions, the good and the bad. So reach out and let us know. Laravel Design is just getting started, and I can't wait to see where we take things. With that being said, I'll hand you back to Taylor. Enjoy the rest of Laracon. Thank you.
All right. Thanks, David.
Whew.
We've covered a lot today. I hope you're super excited about the future of Laravel. I feel like I've never been more excited about what we're building as a team, as a company, and as a community. We've seen some pretty awesome new additions to our ecosystem. Our first-party VS Code extension, container attributes, deferred functions, caching improvements, the concurrency facade, Inertia 2.0 with async requests, polling, infinite scrolling, prefetching, and deferred props. But as you might be suspecting, I do have one more thing. And that's shipping. Laravel developers, I feel like, are known for just freaking shipping. Shipping good apps, working fast, knocking things out. You know what I mean? Like, I just feel like that, that just resonates with Laravel as a community. And as I said, 10 years ago at Laravel 2014, I launched Laravel Forge, and it was a product that changed Laravel. It changed my life. It really, like, kickstarted the whole Laravel as, like, a serious thing, let's say. Um, that I'm working on full-time. Forge made it super easy to ship and manage applications, to manage servers, virtual private servers on cloud providers like AWS, DigitalOcean, Hetzner, and others. Um, and we remain fully committed to that story. Um, we think developers should have the freedom to ship their applications really easy to a cloud provider of their choice and just manage a good old-fashioned server. And Forge is awesome at that. 5 years ago at Laracon 2019, we launched Laravel Vapor. Again, lets you bring your own AWS cloud account, attach it to Laravel Vapor, and ship your application out to AWS Lambda to tap into the full power of serverless full-stack PHP applications for incredible scale on both the web request and the queue layer. And these are awesome tools that we continue to have great ideas for, and we have exciting new stuff we're shipping to these tools soon. But over the years, I've always dreamed of something just a little bit different than Forge and Vapor. Ultimately, a lot of Laravel developers shipping apps don't want to worry about AWS IAM credentials or DigitalOcean accounts. or Nginx configurations, or load balancers, or networking, or firewall rules. They just want to ship. I just want to ship. We just want to ship. And I think the next generation of Laravel developers, they just want to ship awesome applications out to the world, scale them, and secure them really easily. And that's been our focus for a while. Just ship. And it's what I want our theme to be going forward for Laravel. And I believe that Laravel developers deserve amazing products. So about 6 months ago, I started thinking, what if we just built— what if we just built the platform that we've all always dreamed about for shipping Laravel applications? So back in February, I sat at a dinner table in Amsterdam with Joe Dixon, one of the Laravel team members, and he asked me, like, what's the number you'd be happy with? And what he meant was, how long do you think it should take from a new user signing up to such a theoretical platform to having an app out and running on the world with a shareable link that they can send to their friends or their teammates? And I said, 1 minute or less. 1 minute or less. Like, from sign-up to having an app out there with a URL, a real honest-to-goodness app, 1 minute or less. And that became our North Star. From signing in to shipping, from Hello World to Hello Web, it should be 1 minute or less. And I'm happy to report we hit that goal. And we hit that goal with quite a few seconds to spare, actually. And so today I'm excited to show you for the first time the next generation of shipping Laravel apps, and that's Laravel Cloud. Laravel Cloud is a fully managed, infrastructure platform for shipping and scaling Laravel apps. And for me, it's a dream come true. Um, and I hope you like it too. We have had a blast building this thing, and I think the best way to learn about it is just to see it. So today I'm gonna give you the first preview of Laravel Cloud live from this stage. This is an early version of Laravel Cloud, but it's looking pretty dang good, if I do say so myself. So let's just jump right in to the first demo of Laravel Cloud. All right, here we go. Let's pull up the old secret bookmark. Boom. This is the Laravel Cloud dashboard. You can see that I already have a few apps out here. Let's dig into the Beep app. You can see how fast that loads. This is an awesome awesome app to use. And David and the design and frontend team have knocked this thing out of the park about really thinking through the design and flow of this application. And you can see here we have an overview of our app. We have some stats about the app. We can see some of the previous deployments that were made to this app. It's all really great. So, let's go back to our dashboard. We don't really care about these existing apps. We want to build new stuff. So, let's go to Add New. And we'll just add a new application. I don't have to link anything else. I don't have to add any AWS credentials. I don't have to add a DigitalOcean account. I'm just going to add a new GitHub repository. So, let's go ahead and pick this repository, laricon-demo. I've already linked my GitHub account. I'm going to name the application Laricon. I've got my region here in US East, and I'm just going to say create application. All right, I'm here on the application dashboard or landing page, and you can see Cloud kind of gives me this little wizard for walking me through configuring this application a little bit. We're not going to use that right now. I have time to sort of configure the app if I want to, but for now, let's just deploy it. Since Laravel Cloud is fine-tuned for Laravel, most of it is just zero configuration. This is the platform that Laravel and PHP developers have just always wanted, the ability to just ship really quickly. All right, so we can see that our application is building. It's deploying out to Laravel Cloud. We can see all this build output here. We can see that our stack is provisioning. It's getting our cluster ready to serve our apps. That's now finished. All right, this app looks good to go. You can see we have a laravel.cloud URL here, the nice generated URL. We hit the page. Boom. We have a Laravel app up and running.
Woo!
And to deploy that app just took us 25 seconds. 25 seconds from signing into Laravel Cloud. I picked a GitHub repository. I hit deploy. 25 seconds later, we had a laravel.cloud URL that we could share with a teammate. Share with a friend to access our application, our next big idea. Let's go back to Laravel Cloud. What else can we do here? Let's go back to this applications dashboard. I'm in the Laracon project settings screen. You can see here across the top, I can actually, like, change teams. So right now I'm on my personal team where I have my personal projects. I can change between the projects that are on this team really easily. The whole app is just so thoughtfully designed. thoughtfully designed, and easy to use. So what else could we do? I mean, first things first, let's talk scaling, right? Our next big idea is gonna be really big. So we wanna scale up this app. How do we make that happen in Laravel Cloud? Well, let's go to the settings page and go to web. We'll edit this app. We get this nice little flyover here. Let's scale up maybe to the medium size, and we'll make 10 replicas of the app on Laravel Cloud. So 10 instances serving this app. All right, so if we're good with this, let's just hit save, and we'll hit save and deploy. And that's provisioning our fresh application stack. We've scaled the servers vertically and horizontally. So we've upped the power of the servers, and we're deploying to 10 replicas across our cluster. And you can see our app redeploying. And once it's deployed, we can hit the app, and we've already scaled up to be able to handle more traffic on Laravel Cloud. It's that easy to build scalable applications. All right? And this deployment is finished. All right? So our app is scaled up. Super easy. And on the web tab, you can see we have hibernation here. Let me make that a little bit bigger. for you. We have hibernation. If I enable app hibernation, I can tell cloud to put my app to sleep if it hasn't received traffic in a specified amount of time. And the cool thing is I'm not paying for compute while my app is sleeping. So this unlocks so much freedom for Laravel developers, and it was a must-have feature in my eyes for this platform. I want every developer to be able to ship their test projects, ship their side projects, ship their staging environments, and you only pay for the compute you're using. So you never have to worry about, oh, do I really wanna ship that side project to Laravel Cloud? You can put all of your side projects on Laravel Cloud, just turn on hibernation. If they're not being used, you're not paying for any compute. Really great. All right. This is our branch. Pop this open in Sublime Text. And what should we do here? We'll come to our routes file. I'll just make like route GET new route.
All right.
I'll fix my typo here. And we'll just return like hello Laragon. All right, so we've got that in new route. We come back to Git. We have modified this file, so let's commit that. New route. We'll push that up to GitHub. All right, cool. That's been pushed up. And now if we come back to cloud, you can see up here I've got main. That's the branch we're currently on.
Great.
So, we pick new route. It will give us an environment name. Let's just hit create environment. We don't need any help setting this up. We'll just hit deploy. All right. And now our branch is deploying on its own separate infrastructure, separate from our other main branch. And you can see it's deploying out that branch. We get our build output. And then it's going to deploy a compute cluster for this new branch. All right. It's provisioning that infrastructure.
All right.
So this is out there. You can see we have a new laravel.cloud URL. So every environment gets its own unique laravel.cloud URL that you can share with teammates or collaborators.
Cool.
And it's separate from your main branch URL. So let's go ahead and hit that app. And hopefully we can hit the new route URL, and we get hello Laragon. So it's super seamless, super painless. If your team is working on a new feature, to just throw that feature out on Laravel Cloud, let your team test it out, sign off on the feature, and then ship it out to production. It's all really great and really fast. All right, let's go back to this app's dashboard, and maybe let's just switch back to the main environment, our main branch. What else do we need to build a Laravel app? Well, we're full-stack developers, right? We might need a database. So how do we do that in Laravel Cloud? What if we want to add a database to this app? And this particular app is using Laravel Breeze, one of our application authentication starter kits. So we should have a user profile dashboard ready on the app, but we do need a database to power it. Let's go back to Settings. If we go to the Database tab, you can see that I can just hit Enable Database, and that unlocks another selection combo box where I can select or create a database.
Okay?
I'm not going to use that database. It will show me some of the existing ones I can use. I can always attach a database that maybe another app uses if I want to share databases databases across apps. For this app, let's create a brand new database. And you can see we get a few options here. We're gonna create a Laravel Serverless Postgres database. I'm sure many of you know that Postgres is a very popular open source database, maybe the most popular open source database among developers today. With Laravel Serverless Postgres, we can create a database that auto scales based on your application's needs, both for compute and for storage. So you don't really have to pick any compute size or any storage size upfront. We can just create a serverless Postgres database. It's all managed by Laravel Cloud. You don't have to worry about the infrastructure. Let's go ahead and give this database a name. We'll call it Laricon. All right, and we've got a region, and you can see right here we have a sleep after value. So not only can your apps hibernate, your database can also hibernate. And if a request comes in while your app is hibernating, we wake your app up in seconds and route the request to the app, and the user gets a response. They don't get an error. And it's the same with your database. If your database isn't being used, we can hibernate your database so that you're not paying for any database compute while it's hibernating. This means, again, you can ship all the side projects you want, all the staging environments you want, If it's the weekend and your developers aren't working on your app, you're not paying for database compute. Your database is asleep. That's awesome. All right, so let's go ahead and create this database. I want you to watch how fast this happens. We hit Create Database. See this toast right here? The database is being created. And now it's gone. That database is ready to connect to locally. Even from, like, TablePlus, I could connect to that database already. It literally takes a matter of about 5 or 6 seconds to have an auto-scaling Postgres database on Laravel Cloud. All right, so I've attached this database to the app. Let's just go ahead and hit save. All right, so we've saved that change. It hasn't taken effect yet, 'cause we haven't deployed the app. There's one more thing I want to do. I want to come to the deployments tab, and I want to run my migrate— my migrations as a deployment step. If we're gonna have a database, we need to migrate the database every time we deploy. So let's go ahead and enable that. This time I'm gonna hit save and deploy. All right, so it's deploying those changes. And since we enabled a database and attached a database to this app, Laravel Cloud will automatically inject the proper environment variables into the app. So there's no other configuration we need to do. Our app should just be able to connect to this database straight away as soon as our deployment is finished. So we're going to wait for this to finish. It looks like it's deploying the cluster now.
All right.
And this is deployed. So let's go ahead and close out these old tabs. Now, if we hit this app, you can see we have a login and register link, because our app detected we have a database. And Laravel— well, Laravel Breeze, I should say, detected that we had a database. So let's go ahead and register.
All right.
All right, and we're logged in. We have a serverless database backing this application. So we can hit the profile screen. You can see everything feels really snappy. It feels really fast. We have a database. It's all working on Laravel Cloud in a matter of seconds. And when our app's not being used, it can hibernate, so we're not paying for that capacity.
compute.
All right, so that's how easy it is to attach a Laravel serverless Postgres database to a Laravel Cloud app, which I think is just a huge leap forward in how we ship and scale applications. All right, we've added a database. What else might Laravel applications need. We might need queued jobs. On this app, I actually have a podcast route, and on this route, we get this CacheGPT screen where we're using ChatGPT to generate podcast name ideas. Okay, so we'll feed it a topic, and it will give us a podcast name based on that topic. So, let's try a few. We could try I don't know, let's try Laravel, or maybe Seinfeld. What else? Maybe Dolphins. What else?
Star Wars.
Star Wars, all right. All right, so we got 4 out there, that's good. But you can see it's just spinning, and it's because we've queued a job to generate this podcast name, but we haven't actually configured a queue worker on Laravel Cloud. So let's do that now. Let's go back to Cloud. We'll go to Settings. And let's go to web. We'll edit our web instance. And now, if we come down here to the daemons area, we can add any daemons we want on this web instance. So, php artisan queue:work-database, and we can even say how many processes. Let's scale it up. Maybe we want 10 queue processes on all 10 replicas, so that's really a total of 100 workers running across our infrastructure. All right, and let's just save and deploy. Laravel's going to build our app, and it's going to provision all of the daemons that we configure. And we're not limited to just queues. We could run any kind of daemons we want across our infrastructure super, super easily. Laravel Cloud will make sure they're always running and that they're gracefully restarted if they go down. And Laravel Cloud is a serviceful, serverful architecture. Your applications on Laravel Cloud have disk that they can write to, persistent disk. You can use any Laravel feature you want. You can store files locally if you want. It's truly a platform built for developers by developers. All right, so this application has deployed, and you can see we got our podcast because our queue is up and running. So we got Wookiee Wins and Bantha Banter. for our Star Wars podcast, Seinfeld Shenanigans down there, and Laravel Laughs. OK, some great podcast names. All right, so we've got queues up and running. But you'll notice that when I configured these daemons, I put them on the web instance. So we actually let you configure queue workers on the same cluster that is serving your application's web traffic. But sometimes you might not want to do that. So Laravel Cloud also lets you add dedicated workers. This is separate infrastructure that's not serving web requests, where you can put any queue workers you want or any other long-running tasks. So, let's add a worker. I can name it queues, since this is gonna run my queues. I can pick how big I want these servers to be, and I can specify how many replicas I want. Let's do 3 workers. I can say if I want the Laravel scheduler to run. on these workers, and I can add any daemons I want. php artisan queue:work database. Give it 5 processes apiece. And let's save and deploy. Now we've got not only our web layer running queue workers, we're provisioning dedicated workers that are also running our queued jobs. And we can build as many replicas as we want for this application. to build as much scale as we need to, to handle our customers' needs. And everything is smooth and maintained by Laravel Cloud. You don't need to worry about SSL certificates. Every Laravel Cloud app and Laravel.cloud domain comes with free SSL and free basic DDoS protection powered by Cloudflare under the hood. Somehow we've killed our Cast app by deploying a worker. All right, we'll figure that out later. All right, let's go to something that I think you'll all be interested in is, one, when can I use this? And 2, how much is it going to cost? All right, so let's go back to my slides. First, the cost. Our Sandbox plan has no fixed monthly fee. You just sign up to Laravel Cloud and you have an account and you run all the apps you want, and the compute starts at less than a penny an hour to run your Laravel apps, with Laravel Serverless Postgres starting at 4 cents an hour and 75 cents a gigabyte. This includes all the laravel.cloud domains you want, and it includes app hibernation and database hibernation so that you only pay for what you, what you use. So everyone can sign up for Laravel Cloud and deploy all of the projects you want. If they're not being used, you don't pay. If they're being used, you pay nice, predictable, pay-as-you-go pricing for compute and for database. Our production plan, auto-scaling compute supported. Larger instance sizes, and custom domains. We'll have a small fixed monthly fee and then the same pay-as-you-go understandable pricing. No hidden bills. Pricing you can actually understand. And we'll be releasing bandwidth and file storage pricing later this year. So if you want early access— and we want customers on the platform, shipping applications in early access later this year. If you want to be one of the first people to get access to Laravel Cloud, go to cloud.laravel.com and join the early access list. That is the best way to stay updated about what we're working on, on Laravel Cloud, and what you can expect from the platform. So that's Laravel Cloud. What do you think? It's really been my privilege to share all of this hard work that the Laravel team has put in building this amazing features for the framework, for Inertia, for Cloud, our design team, our VS Code extension. So much work that the team has put in over the last 6 months. And I want to thank the Laravel team especially for all the work they've done. It's been a privilege to work with all of you on these products. We have a little bit more to say about Cloud. So if you bookmark this link, we have a special behind-the-scenes interview between me and Aaron Francis, our Laracon MC. We're going to debut this next week. It goes into the whole backstory of why we started building Cloud, why now, how we're making it happen. And I hope you enjoy it. It's a really fun interview with Aaron, and that's going to be out next week on YouTube. Bookmark this link so you can see it as soon as it premieres. So we've seen the future of Laravel, I hope, today. Awesome new framework features, our commitment to open source with our VS Code extension, Inertia 2.0, a breath of fresh air in a frontend world that often feels like it's gone mad. And the future of shipping applications on Laravel Cloud, where every new developer coming into the Laravel ecosystem can just ship, can just ship their next big idea, their next big startup. And so the enterprise teams can scale their applications on Laravel safely and securely and be able to sleep at night. So what about debugging, observing, and monitoring those applications that are in production? For that, tune into Laracon Australia in November, because we'll have a lot more to say on that topic. Thank you, everyone.
Nice job. So like Taylor mentioned, we do have a full interview coming out next week, but if you're up for it, I just have a few questions.
Okay.
Um, you opened by saying that the ethos of Laravel is to ship, ship fast. You said that y'all built this in 6 months.
Yes.
How, how, how many, how many members of the team were involved in that? Um, and what is, I know what the backend is, what is the frontend?
So I would say probably there's around 10 of us involved on the cloud team. Um, but all of us on Laravel, the whole team has of course pitched in.
Mm-hmm.
Their ideas, right? We're all Laravel developers at Laravel. We love Laravel, and we know what we want. We know what we've always wanted in a shipping platform. So the first commit to Laravel Cloud repo, what you saw today, was in April, actually, as far as the frontend goes. Um, the infrastructure team started working on Laravel Cloud a little bit earlier than that, but it is like, it, it does blow my mind how much our team has gotten done so quickly. to essentially rebuild a cloud platform for Laravel from the ground up. So—
While running like 3 or 4 other SaaSes and a huge open source.
Yeah. While running all of our, uh, open source and other products. So I'm extremely proud of the team. It's my, uh, honestly honor to work with people that are much smarter than me on a much daily basis, on an, uh, everyday basis. So yeah, I, I just, it's been my privilege to work with the team on this.
That is incredibly fast. Um, second question, do you think Um, do you think this will be an inflection point when we look back on the history of Laravel?
I think so. Um, when I think back to when I first started shipping PHP apps, it was very common for new web developers to start on PHP. Um, it was just a very common entry point into web development. And lately it feels like not as many people are starting on PHP. And one barrier to that is the ability to ship these apps really easily. Developer expectations have changed. And since we launched Laravel in 2011, and since we launched Forge in 2014, developers just have different expectations on how easy it should be to go from their local machine to production URL. And if it's not like a button click, they're like noping out at this point, you know?
Mm-hmm.
So we knew we needed to build a next-generation platform for shipping Laravel apps, because like I said, I believe Laravel's the best way to build production full-stack applications. If you wanna be productive, if you wanna ship fast, you need to be building on Laravel, and we want to give you the best way to deploy that app that makes it as painless as possible to go from your local machine to production.
Yeah, I love that. Last question. Um, so Laravel team has been cooking. Let's give it up for the Laravel team, by the way. They have clearly been hard at work. Um, so the team has been cooking, you've been heads down. This is the, the realization of a dream. What is your charge to the Laravel community as this inflection point happens?
Um, well, first, thank you for believing in Laravel. Um, I think The fact that Laravel is 13 years old at this point, and this is the biggest Laracon US we've ever done, and people are talking about Laravel and PHP on Twitter and, or on X, and they're not joking about it. You know, all the, it's like actually considered a serious way to ship apps.
Mm-hmm.
And the fact that we're standing in this position all those years later, I think is a testament to this community, the tool we've all built together, and what we believe in. believe in as far as how we like to work and how we like to ship. And so, I mean, I guess my charge to the Laravel community was let's keep working on this thing. Like, I think our best days are ahead of us. And I think the future for Laravel is going to be pretty amazing. And the future for PHP is going to be pretty amazing.
Y'all give it up for Taylor Otwell.
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

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




