Native PHP: Building Full-Featured Desktop Apps with Laravel

Beyond the Browser: The Case for Native PHP

For years, PHP developers remained tethered to the browser. If you wanted to build a desktop application, you typically had to pivot to

for Mac, C# for Windows, or perhaps struggle with the resource-heavy overhead of
Electron
.
Marcel Pociot
changed that narrative at
Laracon US 2023
by introducing
Native PHP
. This framework allows you to take your existing
Laravel
skills and package them into a native desktop binary.

The core problem with cross-platform development is the maintenance burden. Maintaining three separate codebases for different operating systems is a nightmare. While tools like

offer a lighter alternative to Electron by using native webviews, they still require knowledge of
Rust
or complex
JavaScript
bridging. Native PHP bridges this gap by bundling a static PHP binary directly into the application, giving developers full control over the environment without forcing users to install PHP themselves.

Prerequisites and Toolkit

Before you start, you need a basic understanding of the Laravel ecosystem. Native PHP isn't a replacement for Laravel; it’s an extension of it. You should be comfortable with Composer, Artisan commands, and basic frontend concepts.

Key tools used in this tutorial include:

  • Native PHP Framework: The core package that orchestrates the desktop environment.
  • Electron: The default rendering engine used to display the UI.
  • Livewire: A full-stack framework for Laravel that makes building dynamic interfaces simple.
  • SQLite: The portable database engine used for local data storage within the app.

Getting Started with Installation

Setting up your first project is a matter of a few commands. Unlike some starter kits that require a fresh installation, you can add Native PHP to any existing Laravel application. Start by requiring the package through Composer:

composer require nativephp/electron

Once the package is in your project, run the installation command to publish the necessary service providers and configuration files:

php artisan native:install

To launch your application in development mode, use the serve command. This will boot a native window and provide access to developer tools immediately.

php artisan native:serve

Controlling the Window and State

In a web app, the browser controls the window. In a desktop app, you are the pilot. Native PHP provides a Window facade to manage size, position, and behavior. A common requirement is ensuring your app remembers where the user last left it. You can achieve this with the rememberState() method.

Window::new()
    ->title('My Desktop App')
    ->width(800)
    ->height(600)
    ->rememberState();

You can also configure windows to stay "always on top" or define minimum dimensions to prevent the UI from breaking when resized. Because Native PHP uses a service provider model, these configurations feel like standard Laravel development.

Building Native Menus and Events

A true desktop experience requires a native menu bar. Native PHP allows you to define these menus using a fluent API. You can even hook into system-level events. For instance, if you want a "Preferences" menu item to trigger a Laravel event, you can register an EventItem.

Menu::new()
    ->submenu('App', Menu::new()
        ->event(SettingsClicked::class, 'Preferences', 'CmdOrCtrl+,')
        ->separator()
        ->quit()
    )
    ->register();

When the user clicks "Preferences," Native PHP dispatches a standard Laravel event. You can then listen for this event in your EventServiceProvider to open a new settings window. This makes the boundary between the OS and your code almost invisible.

Real-Time Native Communication

one of the most impressive features is the ability to communicate between windows in real-time. By using the Native prefix in

listeners, you can react to system changes instantly. Imagine changing a theme color in a settings window and watching the main dashboard update immediately without a refresh.

// Inside a Livewire component
protected $listeners = [
    'native:settings-updated' => 'refreshUI'
];

Syntax Notes and Best Practices

  • Facades: Native PHP relies heavily on facades like Window, MenuBar, and Settings. These are your primary interfaces for interacting with the OS.
  • Hotkeys: Use strings like CmdOrCtrl+S to ensure your shortcuts work across both Mac and Windows.
  • Storage: Since the app runs locally, use the Settings facade for key-value pairs rather than a traditional remote database when possible.

Practical Tips and Gotchas

Distribution is the final hurdle. When you run php artisan native:build, the framework bundles your PHP source code into the app. Note: Currently, this does not obfuscate your PHP code. If you are shipping a closed-source product, be aware that your source files are technically accessible within the app package.

Additionally, Native PHP handles migrations automatically on startup. This ensures that every time you ship an update with a new database schema, the user's local SQLite database stays in sync without manual intervention. Always test your migration paths thoroughly, as rolling back on a user's machine is significantly harder than on a centralized server.

5 min read