nativeblade / nativeblade
Build desktop and mobile apps with Laravel + Livewire
Requires
- php: 8.3.*|8.4.*|8.5.*
- bacon/bacon-qr-code: ^3.0
- laravel/framework: ^11.0|^12.0|^13.0
Requires (Dev)
- livewire/livewire: ^3.0
- orchestra/testbench: ^9.0|^10.0
- phpunit/phpunit: ^11.0|^12.0
- dev-main
- v1.0.4
- v1.0.3
- v1.0.2
- v1.0.0
- v0.9.22
- v0.9.20
- v0.9.12
- v0.9.10
- v0.9.9
- v0.9.8
- v0.9.7
- v0.9.6
- v0.9.5
- v0.9.4
- v0.9.3
- v0.9.2
- v0.9.1
- v0.9.0
- v0.5.5
- v0.5.4
- v0.5.3
- v0.5.2
- v0.5.1
- v0.5.0
- v0.4.3
- v0.4.2
- v0.4.1
- v0.4.0
- v0.3.5
- v0.3.4
- v0.3.3
- v0.3.2
- v0.3.1
- v0.3.0
- v0.2.9
- v0.2.8
- v0.2.7
- v0.2.6
- v0.2.5
- v0.2.4
- v0.2.3
- v0.2.2
- v0.2.1
- v0.2.0
- v0.1.13
- v0.1.12
- v0.1.11
- v0.1.10
- v0.1.9
- v0.1.8
- v0.1.7
- v0.1.6
- v0.1.5
- v0.1.4
- v0.1.3
- v0.1.2
- v0.1.1
- v0.1.0
- dev-feature/portal
- dev-feature/tests
- dev-feature/blank
- dev-feature/shell
- dev-feature/pre-prod
- dev-feature/nativeblade-push
- dev-feature/switch-php
- dev-feature/database-4
- dev-feature/schedule-6
- dev-feature/filesystem-3
This package is auto-updated.
Last update: 2026-04-19 04:59:44 UTC
README
Build desktop & mobile apps with Laravel + Livewire. No Electron. No React Native. Just PHP.
Configuration • Components • Directives & Attributes • Plugins • Push • Animations • Lifecycle • Database • Filesystem • Build • Scheduler • Auto-Update • Publish
NativeBlade lets Laravel developers build desktop and mobile apps using only PHP and Blade. Your entire Laravel + Livewire application runs inside a PHP WebAssembly runtime, wrapped in a Tauri 2 shell. No JavaScript frameworks. No API layers. Just the Laravel you already know.
Features
- Pure Laravel — Routes, Livewire components, Blade templates, Eloquent (SQLite)
- Tiny Bundle — A full Laravel + Livewire app compresses to ~6 MB gzipped (see BUILD.md)
- Native Shell — Top bar, bottom navigation, drawer, modal, tray — all outside the WebView
- Native APIs — Dialogs, notifications, camera, geolocation, haptics, biometric, NFC, barcode
- Desktop — Windows, macOS, Linux with native menus and system tray
- Mobile — Android & iOS with status bar, safe area, orientation control
- Push Notifications — Server-pushed notifications via FCM (Android) and APNS (iOS) that wake the app even when closed
- Animations — 90+ Animate.css animations + custom NativeBlade animations via
nb-animationattribute - Offline-First — SQLite persisted to IndexedDB, works without a server
- Hot Reload — Vite HMR for instant feedback during development, plus
--buildmode to preview the production bundle locally - Icons — 3,024 Phosphor Icons (regular + fill) included
- Custom Fonts — Offline font loading via base64 embedding
- Page Transitions — Fade, slide, zoom, flip, bounce, blur — powered by Animate.css
Requirements
- PHP 8.3, 8.4, or 8.5 (with GD extension)
- Laravel 11, 12, or 13
- Livewire 3
- Node.js 20+
- Rust — install here
Quick Start
# 1. Create a new Laravel project composer create-project laravel/laravel my-app cd my-app # 2. Install NativeBlade composer require nativeblade/nativeblade php artisan nativeblade:install # 3. Build the frontend npm run build # 4. Launch the desktop app php artisan nativeblade:dev
✓ src-tauri/ — Tauri project
✓ layouts/ — Blade layouts with shell support
✓ vite.wasm.config.js — Vite config for WASM bundling
✓ AppServiceProvider — NativeBlade config
✓ Demo app — Login, Trail, Lesson, Rank, Profile
The first run compiles the Rust binary, which takes a few minutes. Subsequent runs are fast.
Add Mobile
php artisan nativeblade:add android php artisan nativeblade:dev --platform=android --host=192.168.0.10 php artisan nativeblade:add ios php artisan nativeblade:dev --platform=ios --host=192.168.0.10
Mobile requires
--host=<your-local-ip>so the device/emulator can reach the Vite dev server running on your machine. Replace192.168.0.10with your computer's LAN IP (find it withipconfigon Windows orifconfig/ip addron macOS/Linux).localhostwon't work because the phone can't reach your machine through it.
Preview the Production Bundle
Test the exact bundle that will ship — without the Vite dev server and without running a full nativeblade:build:
php artisan nativeblade:dev --build php artisan nativeblade:dev --platform=android --build php artisan nativeblade:dev --platform=ios --build
Builds the frontend once, points Tauri at dist-wasm/, and launches the app. Ideal for validating the real production payload or iterating on Rust/native shell without HMR in the way. See BUILD.md.
How It Works
┌─────────────────────────────────────────────┐
│ Tauri Shell (native window) │
│ ┌──────────────────────────────┐ │
│ │ Top Bar / Header │ ← Shell │
│ ├──────────────────────────────┤ │
│ │ │ │
│ │ iframe (srcdoc) │ │
│ │ ┌──────────────────────┐ │ │
│ │ │ Laravel + Livewire │ │ ← Your │
│ │ │ via PHP WebAssembly │ │ App │
│ │ └──────────────────────┘ │ │
│ │ │ │
│ ├──────────────────────────────┤ │
│ │ Bottom Navigation │ ← Shell │
│ └──────────────────────────────┘ │
└─────────────────────────────────────────────┘
- Boot — PHP WebAssembly loads your Laravel app (8.3, 8.4, or 8.5)
- Migrate — Pending migrations run automatically
- onBoot — Your startup code runs (license check, data sync, API calls) while splash is visible
- Route — Each navigation runs through Laravel's router inside WASM
- Render — Blade/Livewire HTML is rendered in an iframe
- Intercept — Fetch interceptor routes HTTP requests through WASM
- Bridge — Native actions flow through
postMessage - Schedule — Rust timers execute recurring tasks via Laravel Schedule
- Persist — SQLite syncs to IndexedDB automatically
Database
Migrations run automatically on boot — no php artisan migrate needed. Use standard Laravel migrations and Eloquent:
php artisan make:model Task -m
// Migration runs automatically when the app opens Schema::create('tasks', function (Blueprint $table) { $table->id(); $table->string('title'); $table->boolean('done')->default(false); $table->timestamps(); });
// Eloquent works as usual Task::create(['title' => 'Buy milk']); $tasks = Task::where('done', false)->get(); $task->update(['done' => true]);
onBoot Hook
Run code before the app becomes visible. Splash stays up until complete:
NativeBladeConfig::onBoot(function () { $license = Http::get('https://api.myapp.com/license/check')->json(); NativeBlade::setState('license', $license); });
HTTP Bridge, Storage, Eloquent — everything works inside onBoot. See LIFECYCLE.md.
Scheduler
Laravel Schedule powered by Rust native timers. Define in routes/console.php:
use Illuminate\Support\Facades\Schedule; Schedule::call(fn () => SyncService::run())->everyFiveMinutes()->name('sync'); Schedule::call(fn () => CacheService::cleanup())->daily()->name('cleanup');
All Laravel frequency methods work. Overdue tasks execute on next app open. See LIFECYCLE.md.
State Management
use NativeBlade\Facades\NativeBlade; NativeBlade::setState('auth.user', ['name' => 'John']); $user = NativeBlade::getState('auth.user'); NativeBlade::forget('auth.user'); NativeBlade::flush();
Log
Write log entries from any PHP context (Livewire actions, schedules, routes, mount()) and see them in the Tauri devtools console in real time. Works even when PHP crashes mid-execution — the logs written before the crash are preserved.
use NativeBlade\Facades\NativeBlade; NativeBlade::log('App started'); NativeBlade::log('Retrying', ['attempt' => 3], 'warn'); NativeBlade::log('Payment failed', ['error' => $e->getMessage()], 'error'); NativeBlade::log('Query ran', ['ms' => 12], 'debug');
Each level maps to a console.* method and a color in the [NB:<level>] prefix:
| Level | Console method | Prefix color |
|---|---|---|
info (default) |
console.log |
blue |
warn |
console.warn |
orange |
error |
console.error |
red |
debug |
console.debug |
purple |
The context array is rendered as an expandable object in the browser devtools.
Platform Detection
NativeBlade::platform(); // 'windows', 'macos', 'linux', 'android', 'ios' NativeBlade::isDesktop(); NativeBlade::isMobile(); NativeBlade::isAndroid(); NativeBlade::isIos();
Navigation
NativeBlade::navigate('/dashboard')->toResponse(); NativeBlade::navigate('/', replace: true)->toResponse();
<button wire:nb-navigate="/users">Users</button> <button wire:nb-navigate.replace="/">Home</button>
Authentication
// Middleware $user = NativeBlade::getState('auth.user'); if (!$user) { return NativeBlade::navigate('/login')->toResponse(); } // Login NativeBlade::setState('auth.user', ['name' => 'Admin', 'email' => $email]); return NativeBlade::navigate('/', replace: true)->toResponse(); // Logout NativeBlade::forget('auth.user'); NativeBlade::navigate('/login', replace: true)->toResponse();
HTTP Bridge
Laravel's Http facade works transparently — WASM can't make network requests directly, so NativeBlade bridges them through JavaScript:
$response = Http::get('https://api.github.com/users'); // Parallel requests $responses = NativeBlade::pool(fn ($pool) => [ $pool->get('https://api.com/users'), $pool->get('https://api.com/posts'), ]);
Laravel Compatibility
| Works | Via Bridge | Not Available |
|---|---|---|
| Routing, Blade, Livewire | Http facade |
Queues, Mail (SMTP) |
| Eloquent (SQLite) | External APIs | Redis, Memcached |
| Middleware, Validation | Native Filesystem | WebSockets |
| Collections, Carbon | MySQL, Postgres | |
| Service Container | Artisan CLI | |
| Localization | File Storage (S3) | |
| Task Scheduling (via Rust) | ||
| Migrations (auto on boot) |
Documentation
| Doc | Description |
|---|---|
| CONFIGURATION.md | Desktop, Android, iOS configs, permissions, privacy manifest, transitions |
| COMPONENTS.md | Shell components, icons, images, skeleton, fonts, safe area, custom components |
| DIRECTIVES.md | wire:nb-bridge, wire:nb-navigate, nb-feedback, native actions |
| PLUGINS.md | Built-in Tauri 2 plugin bridges (dialogs, notifications, clipboard, geolocation, haptics, biometric, barcode, NFC, opener, OS info) |
| PUSH.md | Server push notifications via FCM (Android) and APNS (iOS) |
| ANIMATIONS.md | nb-animation, Animate.css, custom animations, haptic feedback |
| DATABASE.md | SQLite local, native MySQL/PostgreSQL/MariaDB via Rust bridge |
| LIFECYCLE.md | Boot sequence, onBoot hook, clock sync, migrations |
| SCHEDULER.md | Task scheduling with Rust native timers |
| FILESYSTEM.md | Native filesystem, Storage driver, camera integration |
| BUILD.md | Build command, output, CLI commands, icon generation |
| UPDATES.md | Auto-update for desktop and mobile |
| PUBLISH.md | Publishing to stores |
How NativeBlade Differs
| NativeBlade | Electron | React Native | Flutter | |
|---|---|---|---|---|
| Language | PHP + Blade | JavaScript | JavaScript | Dart |
| Backend | Built-in (Laravel) | Separate | Separate | Separate |
| Binary Size | ~15 MB | ~150 MB | ~30 MB | ~20 MB |
| App Bundle | ~6 MB gzip (full Laravel) | — | — | — |
| Learning Curve | None (if you know Laravel) | Medium | High | High |
| Native UI | Shell + WebView | WebView only | Native | Custom rendering |
| Offline | Yes (WASM + IndexedDB) | Manual | Manual | Manual |
Testing
NativeBlade ships with a three-layer test suite that runs on every push to main via GitHub Actions.
PHP — PHPUnit against Laravel 11/12/13 on PHP 8.3/8.4/8.5 via Testbench:
composer test composer test:coverage # text summary (needs pcov or Xdebug) composer test:coverage-html # full HTML report in build/coverage/
JavaScript — node:test suite covering the runtime bridges (db/http/fs), action handlers and ctx helpers. No browser needed:
npm test
Rust — cargo test suite covering the Tauri command handlers (config, fileops, database row serialization, scheduler). sqlx integration tests use in-memory SQLite:
cd rust cargo test --lib
Run everything locally:
composer test && npm test && (cd rust && cargo test --lib)
Contributing
See CONTRIBUTING.md for guidelines.
License
MIT
Built with Laravel, Livewire, Tauri, and PHP WebAssembly.
Jefferson T.S

