Laravel is perfect for SaaS

Kevin NaidooKevin Naidoo
10 min read

This is a bit different from my regular posts; it's more of an appreciation of Laravel(and PHP). Having worked with many web frameworks like Django, Asp.net, FastAPI, etc... I still come back often to Laravel and love working with it. It's the most productive toolchain for rapid development.

When it comes to building SaaS applications, as a solo dev I need to ship fast, not everything will generate revenue, so you are bound to fail more often than not and need a rapid dev tool to quickly pivot.

Laravel without even installing a single add-on or package, comes with so much functionality out of the box such as mailable's, queue jobs, blade, artisan commands, and more...

Laravel Super hero

SaaS boilerplates are overhyped

If you do a Google search or look in places like Reddit, you'll find loads of Next.js boilerplates. Nothing wrong with Next.js at all, but as a Solo SaaS founder who's self-bootstrapped, having tried a few of these paid products, I don't see the value.

Most just come with basic gluing of components together. Sure, it's lean but having built many web apps before, you'll find most of these starter kits lack real-world features like basic CRON jobs. You need to rely on a third party like Vercel for that !?

Laravel out of the box may be bloated, but if you are a SaaS founder just setting up a new product, this is not a major problem. You can get a couple of $10 VPSs and scale to 1000s of users, at which point if performance does become a problem, you can always optimize queries, cache, and load-balance later.

While there are plenty of paid SaaS boilerplates for Laravel, you'll find often these are not even needed since you can just use one of the starter kits. They already come with Auth, tailwind and even React if you want to use Intertia.

For the backend guys who hate frontend, livewire is a great option or even good old blade using the breeze starter kit.

Laravel has options galore

As eluded to earlier, most of these starter kits or SaaS boilerplates are missing really important components. If you build CRM or business-centric type applications often, one of the major things you need is a solid CRUD builder.

Laravel has plenty of options like Backpack or Filament, even a paid option from the Laravel team called Nova.

Laravel has plenty of options

If you prefer old-school Bootstrap, Backpack works pretty well. For modern tailwind-based stacks either Filament or Nova are really great options.

With a few CLI commands you can scaffold a table and forms. Additionally, most of these tools include nice features like sorting, searching, and filtering so you don't have to manually write all that boilerplate code yourself. In true Laravel nature, everything is extensible, so you can easily customize any of the generated code or override the route completely to build whatever custom functionality you want.

Deploying your application is also a breeze, you can either provision a one-click image for LAMP on popular cloud platforms like Digital Ocean or Hetzner or you can use paid products from the Laravel team such as forge or cloud.

If you prefer to provision things yourself, there's even a CLI tool to help called Deployer.

What about monitoring? Laravel provides a free open-source tool maintained by the core team called Pulse.

Background jobs? You almost always want to send emails and run other long-running processes in the background. Most languages have an "async" feature but the problem is "async" generally does not persist the task, so if the node/process dies you lose the task, plus you can't distribute the load over multiple servers easily.

Laravel makes this a breeze with Horizon, you can easily push tasks to a Redis queue and distribute them across servers with retrying should a node fail. Furthermore, you also get a beautiful dashboard to monitor these tasks.

Disclaimer: All links included in this post are just because I personally used them and liked them, or are well recognized in the Laravel community. None include paid affiliations.

The beauty of Laravel is that the core team maintains a large selection of tools and packages, making it much less stressful to deal with 101 different dependencies from smaller projects that might run out of funding or stop maintaining the code.

What do I dislike about Laravel?

Okay, to be fair it's not all sunshine and roses. Laravel as mentioned earlier can be bloated, thus the learning curve is much steeper for new developers and can be a tad bit overwhelming too.

Dislike about Laravel

Luckily, the Laravel docs are some of the best docs out there and if you are a visual learner, there's also Laracasts. Not forgetting the large community on Reddit and other similar platforms, there's always a friendly Laravel dev to help you out.

Laravel can be magic sometimes; Laravel is razor-focused on making the developer experience as pleasant as possible, which is great! But this also creates a high level of abstraction which can be a pain sometimes when debugging or trying to figure out what's going on under the hood.

Lastly, the framework moves fast. This means they sometimes break things, especially when moving between major versions. Furthermore, they tend to introduce too many new features which can be distracting or annoying if you have been using something for a long time and then they switch to something else.

A good example is "blade". Blade was the first template engine since forever, and still is the default template engine for Laravel but in the recent Laravel 12 version, the installer no longer has an option for Laravel Breeze (they may bring it back). We now can only pick between "React", "Vue" or "Livewire".

To be fair Livewire is built on top of blade, so you can still use blade that way but there are many purists in the community who just prefer the standard blade option and were quite upset by this decision.

The good news is that while Laravel may no longer recommend an option or advertise it, the core team still tends to maintain old packages. So if you picked Breeze or even Jetstream (which is a tailwind-based blade template), you may not get any new features but at least you'll still get security and bug fixes for many years to come.

In summary, while Laravel is a large framework by the number of features it ships, and sure they do tend to move fast, still you have the support and backing of the Laravel core team working tirelessly behind the scenes to keep the framework stable and up-to-date.

As a SaaS builder, this is great, because I know I can rely on a mature framework that will still be around in 10 years!

Which Laravel starter kit should I pick?

Laravel has many options for rapidly scaffolding an auth system with a basic dashboard. A common debate for newcomers is which starter kit to pick.

If you come from the React/JS world, Interntia is probably the best choice for you because it’s very similar to Next.js. Laravel handles all the routing, DB queries, and other backend stuff but passes the data to React by means of props. From there on out, you can use shadcn and regular old React. This makes life super easy, no need to build separate APIs or mess around with server components.

A similar approach applies to Vue If you prefer that stack.

For those who don’t like JavaScript or want to avoid it like the plague, then Blade is a good option with the Breeze starter kit. Even though it is no longer part of the default choices in Laravel 12, it’s still supported and widely used.

With Breeze, you can build out your application using conventional MVC-style development. You process data on the server side, and then just pass that data down into the template for display. Blade is a server-side template language that’s easier to work with and much cleaner to use than raw PHP.

If you need a more complex UI but want to avoid heavy JS frameworks, another option is Livewire. Livewire is an extension of Blade, thus you can easily mix and match Blade and Livewire in the same project without much fuss.

Livewire makes building dynamic interfaces simple, you basically can use PHP on the server side to manage state and generate dynamic features in your app without touching javascript. Under the hood Laravel will use AJAX calls to wire frontend events to Livewire components, making it look and feel similar to developing in React, without all the complexity of React.

While Livewire is a decent option for small applications, in really complex and high-traffic applications, I don’t recommend it. The performance is not that great and there are several weird quirks you end up jumping through hoops to figure out. Furthermore, there aren’t many mature UI libraries that support Livewire.

What about billing?

Laravel provides a nifty little package called Cashier. Cashier works really well regardless of whether you use Stripe or Paddle, with just a little bit of configuration, you can have a full working subscription-based billing system within minutes including all the webhook endpoints and management of subscriptions.

While Cashier will save you hours if not days of work, there’s even a faster way to get a complete billing system up and running. The Laravel core team provides a paid all-in-one complete billing system that can just plugin into any Laravel project called spark.

What about CRUD?

As mentioned earlier, there are many options to speed up boring old CRUD in Laravel. Filament is by far the most popular and widely accepted CRUD panel generator for Laravel. Here’s a basic example of what filament can do with just a few lines of code:

public function form(Form $form): Form
{
    return $form
        ->schema([
            TextInput::make('title'),
            TextInput::make('slug'),
            RichEditor::make('content'),
        ]);
}

What about tables?

public function table(Table $table): Table
{
    return $table
        ->columns([
            TextColumn::make('title'),
            TextColumn::make('slug'),
            IconColumn::make('is_featured')
                ->boolean(),
        ]);
}

Wait what about AI?

PHP is not designed for machine learning. Nonetheless, since LLMs are so powerful these days and just an API call away, there’s no need for PHP to directly manage or interact with models. Instead, you can just use OpenAI’s or Anthropic’s API.

You could use CURL directly, or Laravels handy HTTP library, but why do that when we have Prism?

Prism is an open-source library for Laravel that makes dealing with LLMs a breeze, using a few lines of code, you can build robust AI-powered apps in minutes using a clean and fluent syntax. Example:

$response = Prism::text()
    ->using(Provider::Anthropic, 'claude-3-sonnet')
    ->withSystemPrompt(view('prompts.system'))
    ->withPrompt('Explain quantum computing to a 5-year-old.')
    ->generate();

Prism has pretty good support for all the major AI vendors including Gemini, Anthropic, OpenAI, and even DeepSeek.

Using the provider syntax as per above, you can easily swap between these vendors without changing too much of your code.

Sending emails is a breeze?

One of the most common things you’ll do in most web applications is to send emails. Laravel makes these super simple, and in addition to just sending emails, you can easily dispatch that mail to a queue and process it in the background.

Here’s a basic example using Mailable classes.

Mail::to($request->user())
    ->send(new OrderShipped($order));

“OrderShipped” would be similar to a Controller where you render either a Markdown or HTML template. Learn more about writing mailables here.

What about Async tasks?

Generally in Laravel, queues are the preferred way because tasks are stored in Redis and can be distributed across multiple nodes and servers, plus if a node goes down, you can easily just pick up the task on another node.

If you come from the TypeScript/JavaScript world, you will most likely be very familiar with “async and await” but does this work in Laravel? Well no, not exactly because PHP natively does not support asynchronous programming, however, thanks to a little bit of Laravel magic this is totally possible using the Concurrency facade. Example:

Concurrency::run([
    fn () => Mail::to($user)->send(...),
    fn () => Mail::to($user2)->send(...),
]);

PHP by default will run code top-to-bottom and block the process until each line completes. With the Concurrency facade, you can run multiple tasks concurrently and speed up the execution of your program similar to using “async” in JavaScript. Learn more about concurrency here.

0
Subscribe to my newsletter

Read articles from Kevin Naidoo directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Kevin Naidoo
Kevin Naidoo

I am a South African-born tech leader with 15+ years of experience in software development including Linux servers and machine learning. My passion is web development and teaching. I often love experimenting with emerging technologies and use this blog as an outlet to share my knowledge and adventures. Learn about Python, Linux servers, SQL, Golang, SaaS, PHP, Machine Learning, and loads more.