A few months ago I had a client come to me with a familiar problem. They had a solid Laravel SaaS, their users loved it, but a handful of those users kept asking for a desktop version — something they could run offline, pin to their taskbar, and not worry about browser tabs accidentally closing. The client assumed that meant a separate codebase, a new tech stack, and probably a six-month project. I had a much more interesting answer for them: NativePHP.
If you haven't looked at NativePHP yet, now's the time. It's a framework that lets you build desktop applications using PHP — specifically using Laravel — and package them as native Windows, macOS, or Linux apps. It wraps Electron or NativePHP's own runtime under the hood, but you stay in Laravel the entire time. Your routes, your models, your service classes — they all come along for the ride.
Let me walk you through how I approached this project, what surprised me, and the patterns I now reach for when a SaaS needs a desktop companion.
Why NativePHP Clicks for Laravel Developers
The reason NativePHP feels so natural is that it's not asking you to learn a new paradigm. You're still writing Laravel. You still have php artisan commands, you still write Blade views or Livewire components, and you still think in terms of controllers and routes. The difference is that instead of serving HTTP requests from a remote server, Laravel runs locally on the user's machine inside a packaged application.
This is a genuine shift in mindset — from server-side to embedded — but because the code looks the same, you can move fast. I was able to take about 70% of my client's existing service layer and drop it straight into the NativePHP project with almost no changes.
Getting the Project Set Up
Installing NativePHP into a fresh Laravel project is straightforward:
composer require nativephp/laravel
php artisan native:install
From there you get a NativeAppServiceProvider where you define what happens when your app boots — things like window size, menu bar configuration, and system tray behaviour. It feels like any other service provider, which is reassuring.
use Native\Laravel\Facades\Window;
public function boot(): void
{
Window::open()
->width(1200)
->height(800)
->title('My App');
}
For my client's project I spent the first afternoon pulling in the shared SaaS logic as a local Composer package, which kept things clean and meant bug fixes applied to both the web version and the desktop version simultaneously.
Livewire on the Desktop
Here's where it gets really enjoyable. Because NativePHP runs a full Laravel app with a local HTTP server, Livewire works exactly as you'd expect. I built the entire desktop UI using Livewire v3 components and Flux UI, styled with Tailwind CSS v4. It felt completely normal — I was just building a Livewire app.
There are some areas to be thoughtful about though. Network requests to external APIs still need connectivity, so I added clear offline-state handling using Alpine.js to watch the browser's navigator.onLine and surface friendly messages when the user drops off the network. Something like this:
<div x-data="{ online: navigator.onLine }"
@online.window="online = true"
@offline.window="online = false">
<template x-if="!online">
<p class="text-amber-600">You're offline — some features may be unavailable.</p>
</template>
</div>
Small touches like this make a desktop app feel genuinely native rather than just a browser in a box.
Local Storage and SQLite
One of the nicest things about building a desktop app with NativePHP is that SQLite becomes your default database, and Laravel's SQLite support is excellent. Migrations run on first launch, the database lives in the user's app data directory, and you get all the Eloquent goodness you're used to.
For my client's app, I used SQLite for local caching of data the user had already fetched, and a sync mechanism that pushed changes back to the central SaaS database when connectivity was available. This is the kind of architecture that used to require a dedicated backend team — but with Laravel's queue system running locally and some careful event dispatching, I had a working sync in a few days.
What I'd Warn You About
NativePHP is still maturing. The documentation covers the essentials well, but you'll hit edge cases that require digging into GitHub issues or asking in the Discord community. I ran into a few gotchas around file permissions on Windows that took longer than I'd like to admit to resolve.
Auto-updating is also an area where you need to plan ahead. NativePHP has update support, but how you distribute and sign your app varies significantly by platform. macOS notarisation in particular is a process you want to research before you promise a release date to a client.
That said, none of these are blockers. They're just things to budget time for.
Who Should Consider This
If you're a Laravel SaaS builder and any of these sound familiar, NativePHP is worth a serious look:
- Your users need offline access or want the app to feel more native
- You have business logic you've already built and don't want to rewrite
- You want to offer a desktop companion app without hiring a separate team
- You're building a tool that interacts with local files, system resources, or hardware
I've also found it genuinely enjoyable for internal tooling. Shipping a desktop app to a small internal team is far simpler than deploying a web app with auth, SSL, and all the trimmings — and NativePHP lets you package something up in an afternoon.
Final Thoughts
I've been a Laravel developer for a long time now, and one of the things I love most about this ecosystem is how it keeps finding ways to extend into new territory without asking you to start over. NativePHP is a brilliant example of that. You don't need to learn Electron, you don't need to pick up Rust or Swift, and you don't need to maintain two completely separate codebases.
You write Laravel. You ship a desktop app. That's a pretty good deal.
If you're building a SaaS and your users have been asking for a desktop version, I'd genuinely encourage you to spin up a NativePHP project and spend a day exploring. You might be surprised how much of your existing code makes the trip with you.