On Laravel, Full-Stack JavaScript, and Productive Frameworks
Iāve been a professional web developer for like 15 years: small websites with WordPress; Rails and Next.js for apps at big companies. Iāve designed a couple React meta-frameworks. Iāve used Laravel to build a side-project over the past five years.
Lots of people are talking right now about whether Laravel and Rails are better than full-stack JavaScript frameworks. Which is better for developers? Which has more hype? Which is more fun to use?
Here are some thoughts on everything from me, a random guy on the Internet!
Iām insanely productive with Laravel
Note: For the purposes of this section, you can pretty much swap in āRailsā for āLaravel,ā because I think the ecosystems are similar and you can reach this level of productivity in both.
So, Barkpass is built with Laravel.
I created the project in 2019 as a Laravel API backend with a Next.js front-end. Separate repos, separate deploy pipelines.
The separation part sucked. I found myself having to duplicate everything, from authentication to authorization to form validation on both the front-end and the back-end.Ā
Solutions like Inertia now exist to solve this problem, but about a year into my Barkpass journey, I scrapped the front-end and started rebuilding it 100% in Laravel.
What does this look like five years later?
- Laravel forall the things: Blade views and components, routing, controllers, authorization, authentication, queues, scheduled jobs
- Livewire for modern interactivity: Form mutations without a browser refresh, SPA-like navigation between pages, full-page components, lazy loading, fancy data tables with filtering, search, pagination
- Official Laravel packages: Nova for super-admin stuff, Horizon for queue management, Pulse for monitoring, Scout for full-text search, Jetstream for team management, Sanctum for auth scaffolding, Cashier for payments, Pennant for feature flags
Iām up to date on the latest versions of everything, so when Taylor and crew drop a new feature, I can start using it right away. This is super fun.
Like the heading says: Iām insanely productive in this stack. If I want to add a new feature, I can start by running:
php artisan make:model Foo -mft
Which gives me:
- An Eloquent (Laravel) Model
- A migration
- A factory for tests
- A unit test
Pretty dope.
If I feel like it, I can start doing some TDD to drive out API design and functionality. Or I can just drop in and start building visually.
Oh, time to add a new interactive piece of UI?
php artisan make:livewire foo --test
Which gives me a new Livewire component and a test for the component. If the component is pretty straightforward, I can route directly to it by defining a Route::get()
to it! No need for a controller. Slap some authorization middleware on the route definition, and boom.
Instead of having to build out an explicit REST or GraphQL API, and then re-implementing all these things in a React or Vue front-end, itās just all happening in PHP. Which feels lovely and liberating and powerful.
A couple things I need to call out here have made my experience in Laravel a delight, and would absolutely not be the case if they didnāt exist:
- Blade components. Components are like your traditional server-side partial, but with special superpowers like composability. The ability to compose UI with HTML-like syntax has been an absolute game-changer:
<x-foo :bar=ā$thingā />
is actually way more appealing for me than@component(āfooā, [ābarā => $thing])
in that it makes me feel like Iām writing cool React code. - Caleb Porzio. Caleb created Livewire, which IMO gives Laravelās Blade view compiler super powers. Modeled after Phoenix LiveView along with cousin Hotwire in the Rails space. The fact that I donāt have to write any JavaScript to be able to have interactive form submissions, SPA-like navigation, and more is incredible. But thatās not all: Caleb also created and maintains Alpine, which I like to think of as āsprinkles of JS,ā along with screencasts and guides for handling the more tricky UI bits like dialogs, data tables, and dropdowns. Where Laravel gets me 90% of the way, Caleb is honestly the last 10% of the ecosystem which is the most crucial for getting things right.
I wonāt spend any more time gushing about Laravel because I think there are problems, too, and there are merits to the full-stack JavaScript story!
Where Laravel falls short
Again, swap in Laravel here for other non-JavaScript full-stack solutionsā¦
If youāre a Laravel developer reading this and looking for hard problems to solve: hereās your list.
Missing that āfront-endā niceness
Laravel applications have been rated lower than alternatives when it comes to accessibility. Iām not an accessibility expert nor will I make any claims about it, but I will reframe this point into a more generic theme:Ā
The quality of front-end solutions does not match that of JavaScript frameworksā¦ yet.
You guys, thereās a reason solutions like Angular, Vue, React, Svelte etc exist. Itās because building the really interactive stuff well requires a ton of work!
But Josh, we have a lot of cool new modern APIs and Vanilla JS works just fine andā¦!
Yeah I totally hear you, and weāre getting closer. But letās step back and look at my own project, Barkpass, for a minute:
Itās built with Laravel and Livewire, so most of my interactivity happens as Livewire sends HTML payloads across the wire and makes server round trips. That can be slow āĀ Iāve found this out the hard way š
So what do you do when itās slow? What do you do for users with slow or intermittent network connections? You start writing client JavaScript.
Alpine is the blessed solution in the Laravel/Livewire space, so you start adding x-data
attributes into Livewire Blade components. A click handler here, an event listener there. It works! Ship it!
Unfortunately, this leaves a lot to be desired in some cases when it comes to not only accessibility, but also type safety, framework upgrades, and resiliency.Ā
The reason front-end frameworks like React Aria, Headless UI and Reach UI are so popular is that their creators have put an incredible amount of work into getting the details right. JavaScript frameworks like React Router, Remix, and Next.js also excel at data fetching, mutations, and optimistic UI.
Iām bummed to say that in Laravel land, youāre kind of on your own in this space. You really have to do the work yourself to learn about all the edge cases and acceptable solutions for accessibility. Caleb is doing work in this space with Headless Alpine UI components. Iām using these in Barkpass, and Iām eager to see these shipped to the world in a stable release!
But Iāve personally been burned by framework and package upgrades, like moving from Livewire v2 to Livewire v3, resulting in lots of uncaught client-side errors for my end users becauseā¦ I didnāt catch them!
Thereās no TypeScript runtime or linter to catch these issues. I guess I could run every single permutation of every action on every page through an E2E test and check for JS errors in the consoleā¦? But I know that we donāt have these issues over on the JS framework side.
Finally, while some of the stuff built into Livewire feels like building with composable React components, in realityā¦ itās not.
For example: you have to be super careful when composing Livewire components: in some cases, you need to define a unique key. In other cases, you donāt.
Livewire provides a āmorph markerā feature which provides hints to the client-side DOM morph logic, but that breaks if you cache your views in production (which you probably do).
Sometimes, you can mark a property as āreactiveā so it responds to updates, but in some cases, that falls short.
Itās the kind of stuff that wouldnāt happen in React land, but itās a tradeoff Iām willing to accept for now!
Verbosity and lack of tooling
To combat the āLaravel is PHP and old schoolā and āwhy do I have so many files in this new projectā arguments, youāll see developers throw around code snippets written in Laravel Volt, or showcase file-based page routing with Laravel Folio. The Laravel team also stripped down the footprint of the starter template drastically in Laravel 11.
Volt and Folio are really great, and I think they showcase just how cool this ecosystem isā¦ but weāre still not there.
For starters, important tooling is missing. I use VS Code, along with a ton of other people, and my IDE canāt figure out that Iām writing PHP code at the top block of a Laravel Volt component. Like, the LSP is completely confused.Ā
This is a solvable problem (again, take note, eager beavers), but itās a deal breaker for the authoring experience.
Another bummer for me is that, while I love the composability of Blade components, I canāt write more than one component in a single file. In fact, it reminds me of one of my chief complaints about Vue, too.
Itās super easy to compose a complex component into sub-components in React! Just create a new function block below and reference it in the same file.
In Laravel, I have to create yet another file in my already-huge list of /components
Again: opportunity for Blade super nerds out there.
Finally: gosh it would be nice to have a proper formatting solution for Blade components. Prettier exists in this space for JavaScript projects, and Laravel Pint solves the problem for PHP classes, but not Blade components. I would pay someone American Dollars to not have to format a Blade file manually ever again.
Solvable problem.
Hosting costs money
In short: You gotta pay to host Laravel and other PHP apps. Even the hobby ones.
Compared to the JavaScript ecosystem which boasts free hosting for projectsāCloudflare Pages, Vercel, Netlifyāthis is a bummer.
Iāve tried and failed to build a liāl free hosting platform for PHP apps. Laravel Vapor is really neat, but it costs money and is geared toward business users. Alsoā¦ AWS.
If I find dozens of hours of free time, Iām going to find a way to compile a real production Laravel app into WASM and deploy it to something like Cloudflare Pages. Weāll make it happen. Someday.
JavaScript and adjacent frameworks are exceptional at front-end things
I think one of the primary reasons people use JavaScript frameworks like Vue, Next.js, and Remix are that theyāre really powerful to use on the front-end.
In most cases, the bar to entry is also really low. These days, you can pop into StackBlitz and start editing right in your browser.
For all the reasons mentioned above, JavaScript frameworks do the front-end really well. But you need a back-end, too, for routing and server rendering, which is why things like SSR in Next.js and Remix, and more recentlyāReact Server Componentsāare born.
Shopify uses React and React Router heavily in its web app. Complex interactions on the UI call out to GraphQL requests which get handled by a Rails app.
The deployment story is also really great for these frameworks. In recent years, hobby projects are all free to deploy, especially if they receive little to no traffic.
If I change the props of my component in one part of my TypeScript app, the rest of my application will fail to build because I havenāt updated the props everywhere else. Thatās really neat. I can also upgrade frameworks and have tests fail where I need to update things.
There are a plethora of resources for interactive components. Tailwind UI and shadcn/ui allow you to literally click to copy a really complex UI that would take hours to build otherwise.
So tl;drāin my experience, itās hard to beat the experience of building a really complex front-end web application in a modern JavaScript framework.
What about āfull-stack JavaScriptā?
Dang it if there isnāt just a huge opportunity here.
Unless you already have a backend service, it feels like youāre kind of on your own as a developer in the JavaScript ecosystem. Well, besides one of the bazillion third-party libraries or services which attempt to solve basic problems like authentication, authorization, form validation, queues, scheduled jobs, and more.
Why hasnāt anyone cracked this yet?Ā
Well, they have: Adonis exists, but nobody knows about it.Ā
I like a lot of things about Adonis, but I think their critical adoption mistake was to not hitch their wagon onto the popularity of existing front-end frameworks like React or Vue. Instead, theyāve built their own view rendering library. Theyāve also copied almost every one of Laravelās design patterns, a little too closely, IMO.
Friction
I also think thereās an enormous amount of friction when it comes to piecing everything together in the JavaScript ecosystem.Ā
I know I just complained about PHP hosting costing money (lol) but once youāre there, itās super straightforward. If youāre running PHP, youāre running Laravel.
Also: if youāre running PHP, you probably also have access to a VPS or a real server somewhere, which means you have access to run additional processes for queue workers, scheduled jobs, databases, and cache.
Unless youāre deploying your JavaScript app to production in a VPS or Docker Kubernetes dealy, youāre gonna have to answer a lot of questions:
- What runtime? Node.js or v8 or Deno or Bun? This will make a difference for the dependencies that you can use. Youāve probably been using Node.js as a development server, but those things will break in production when you deploy to Cloudflare Workers.
- What about your bundler? Did you use CJS or ESM to write that package? Webpack, Vite, esbuild, SWC? How old are the versions? Do they play well together? Bundling and compiling is great for type safety and abstractions, but boy do you pay for it over time with version and tool creep.
- How are you gonna do the full-stack things? Are you connecting to a 3p for a database? What ORM are you using, and what limitations does it have? Where is the database located, and is your deployment going to cause a bunch of latency based on the database location? Can you even communicate with your database over TCP in your production runtime?
Again, remember: PHP (or Ruby, etc) means you can deploy somewhere and have access to these things on your server.
Can existing JavaScript frameworks move to āinsanely productiveā full-stack status?
Yes, I think they can!
As Iām writing this, my former coworker Chance writes about Remixās latest decision to double-down on the next version of React Router:
Now that itās ājust React Routerā (not a real technical distinction btw) I think it might click more easily for some. Build an opinionated, battery-packed Laravelesque framework on top of a relatively thin layer that handles routing.
Iāve started on something like this with Superflare. It removes the friction listed above because Cloudflare does all of the things: database, queues, scheduled jobs, durable objects. But obviously itās super opinionated to just one runtime (Cloudflare).
I think I can keep pushing with Superflare and potentially make it even more agnostic with drivers for Vercel, Netlify and other providers for things like databases and file storage.
However, one of the biggest problems about building a full-stack JavaScript framework is that you have to address routing. Routing is super key because it handles the request and response lifecycle. That also means handling things like cookies, which then relates to session management, which then relates to authentication.
Thatās why I think Chanceās comment is so spot-on: you gotta lean into existing popular frameworks like React Router to do the hard parts like routing, and then add all the fun stuff around it.
Plus, there are exciting things on the horizon: React Server Components gets you even closer to making the front-end š¤ the back-end more fluidly, and Cloudflare just announced Workers RPC for properly splitting up an application into multiple workers. This type of stuff could really be the bread and butter behind a new full-stack JavaScript framework.
If you want to build this with me, hit me up.
Can Laravel and existing full-stack frameworks move to āextremely good at front-endā status?
Yes, probably!
I think this involves creating lots of new tooling around developer experience for front-end things. Do the (good) things TypeScript offers for the ecosystem, but in the backend Laravel and Rails world.
Thereās also a huge opportunity for someone to create the next āHeadless UIā for server-rendered frameworks like Laravel and Rails. Like, do it super well. So I can upgrade my things and not have to rely on users or error tracking services to make sure I didnāt miss anything.
Take accessibility really seriously, and handle optimistic UI and fault tolerance with the care and dedication that the JavaScript frameworks have.
Oh, also: somebody please build a good hosting service that I can just php artisan deploy
to and not have to worry about managing a server or paying somebody like $500/year to manage it for me.
ā
Anyway, I love all of you. You are all great. Keep building cool things.