This guide provides step-by-step instructions for upgrading between major versions of Laravel Starter.
- General Upgrade Tips
- Upgrading to Livewire 4.0 SFC
- Upgrading to 13.0 from 12.x
- Upgrading to 12.20.0 from 2.x
-
Backup Everything
# Backup database php artisan backup:run # Commit your changes git add -A git commit -m "Backup before upgrade"
-
Review Documentation
- Read CHANGELOG.md for all changes
- Check this upgrade guide for version-specific steps
- Review breaking changes carefully
-
Test Environment First
- Always upgrade in development/staging first
- Run full test suite
- Test critical user flows manually
-
Clear Caches
php artisan view:clear php artisan config:clear php artisan route:clear php artisan cache:clear
-
Run Tests
php artisan test -
Review Error Logs
- Check storage/logs for any issues
- Monitor application behavior
Estimated Time: 1-2 hours per component
Difficulty: Low to Medium
Risk Level: Low (with proper testing)
Livewire 4.0 introduces native Single-File Components (SFC) that allow you to define a component's logic and template in a single .blade.php file using the new class extends Component syntax.
- PHP 8.2 or higher
- Livewire 4.0 or higher
- Laravel 13.x
Livewire 4.0 provides native SFC support without requiring Laravel Volt:
<?php
use Livewire\Component;
new class extends Component {
public $title = '';
public function save()
{
// Save logic here...
}
};
?>
<div>
<input wire:model="title" type="text">
<button wire:click="save">Save Post</button>
</div>The make:livewire command now adds emoji prefixes to component files for better visual organization:
| Component Type | Emoji Prefix | Example |
|---|---|---|
| Pages | ⚡ | ⚡ terms.blade.php |
| Forms | 📝 | 📝 contact.blade.php |
| Tables | 📊 | 📊 users.blade.php |
| Cards | 🃏 | 🃏 profile.blade.php |
| Modals | 🪟 | 🪟 confirm.blade.php |
The config/livewire.php file has been updated to support SFC:
'make_command' => [
// 'type' => 'class', // Match v3 behavior (not SFC)
'emoji' => true, // Add emoji prefixes to file names
],# Update Livewire to version 4.0
composer update livewire/livewire
# Clear caches
php artisan view:clear
php artisan config:clear
php artisan cache:clearEnsure your config/livewire.php has the correct settings:
'make_command' => [
'emoji' => true, // Enable emoji prefixes
],
'component_locations' => [
resource_path('views/components'),
resource_path('views/livewire'),
],For each component you want to migrate to SFC:
-
Identify the component
- Find the PHP class file (e.g.,
app/Livewire/Frontend/Terms.php) - Find the Blade view file (e.g.,
resources/views/livewire/frontend/terms.blade.php)
- Find the PHP class file (e.g.,
-
Create the SFC file
- Create a new
.blade.phpfile in the appropriate directory - Use the emoji prefix (e.g.,
⚡ terms.blade.php)
- Create a new
-
Convert the component
Before (Traditional):
PHP Class: app/Livewire/Frontend/Terms.php
<?php
namespace App\Livewire\Frontend;
use Livewire\Attributes\Title;
use Livewire\Component;
#[Title('Terms and Conditions')]
class Terms extends Component
{
public function render()
{
$title = 'Terms and Conditions';
$company_name = app_name();
return view('livewire.frontend.terms', compact('title', 'company_name'));
}
}Blade View: resources/views/livewire/frontend/terms.blade.php
<div>
<h1>{{ $title }}</h1>
<p>Welcome to {{ $company_name }}!</p>
</div>After (SFC):
Single File: resources/views/livewire/frontend/⚡ terms.blade.php
<?php
use Livewire\Attributes\Title;
use Livewire\Component;
#[Title('Terms and Conditions')]
new class extends Component {
public $title = 'Terms and Conditions';
public $company_name;
public function mount()
{
$this->company_name = app_name();
}
};
?>
<div>
<h1>{{ $title }}</h1>
<p>Welcome to {{ $company_name }}!</p>
</div>-
Delete old files
- Remove the PHP class file
- Remove the old Blade view file
-
Test the component
- Visit the page that uses the component
- Verify all functionality works correctly
Routes typically don't need to change, but verify they still work:
// Before
Route::livewire('terms', \App\Livewire\Frontend\Terms::class)->name('terms');
// After - Livewire auto-discovers SFC files
Route::livewire('terms', 'frontend.⚡ terms')->name('terms');
// Or just use the component name without emoji
Route::livewire('terms', 'frontend.terms')->name('terms');Update test references to use the new component format:
// Before
Livewire::test(\App\Livewire\Frontend\Terms::class)
// After
Livewire::test('frontend.terms')
// Or
Livewire::test('frontend.⚡ terms')Traditional class-based components (separate PHP and Blade files) continue to work in Livewire 4.0. You don't have to migrate all components at once.
SFC components don't use namespaces. The component is defined inline:
// Before - Class-based
namespace App\Livewire\Frontend;
class Terms extends Component { }
// After - SFC
new class extends Component { }In SFC, the render() method is optional and typically just returns:
// Before
public function render()
{
return view('livewire.frontend.terms', compact('title'));
}
// After - SFC (optional)
public function render()
{
return; // Just return void or omit the method
}Migrate components in this order to minimize risk:
- Simple static components (Terms, Privacy, Home)
- Form components (Login, Register, ForgotPassword)
- List components (UsersIndex, PostsIndex)
- Complex components (ProfileEdit, PostEdit)
# Clear view cache
php artisan view:clear
# Clear config cache
php artisan config:clear
# Verify component location
ls resources/views/livewire/frontend/# Clear route cache
php artisan route:clear
# Check route list
php artisan route:listEnsure you're using the correct attribute syntax:
// Correct
#[Validate('required|string|max:255')]
public $name = '';
// Incorrect
public $name = ''; // Missing validation attributeIf you need to rollback a component migration:
# Restore from git
git checkout app/Livewire/Frontend/Terms.php
git checkout resources/views/livewire/frontend/terms.blade.php
# Delete the SFC file
rm resources/views/livewire/frontend/⚡ terms.blade.php
# Clear caches
php artisan view:clear
php artisan cache:clearEstimated Time: 30-60 minutes
Difficulty: Low to Medium
Risk Level: Low (with proper testing)
- PHP 8.4 or higher
- Laravel 13.x
- Composer 2.0 or higher
- Node.js 20+ and NPM 10+
Shared frontend components (header, footer, nav-item, button, dynamic menu) have been moved to the nasirkhan/laravel-cube package. References to the old standalone Blade component files must be updated.
Before (12.x):
<x-header />
<x-footer />
<x-nav-item :item="$item" />After (13.0):
<x-cube::header />
<x-cube::footer />
<x-cube::nav-item :item="$item" />Application settings are now managed by the nasirkhan/module-manager package. Any custom settings code that was in the application layer should be reviewed against the package.
composer updateEnsure composer.json requires "laravel/framework": "^13.0" and "php": "^8.4".
Search your views for any overridden or custom copies of the old frontend components and update them to use the cube namespace equivalents.
php artisan migrateVersion 13.0 adds indexes to the user_providers table via a new migration.
php artisan clear-allnpm install
npm run buildphp artisan testEstimated Time: 30-60 minutes
Difficulty: Medium
Risk Level: Low (with proper testing)
- PHP 8.3 or higher
- Laravel 12.x
- Composer 2.0 or higher
- Node.js 18+ and NPM 9+
Before (2.x):
// Modules always in Modules/ directory
use Modules\Post\Models\Post;
use Modules\Post\Http\Controllers\PostController;After (12.20.0):
// Modules in vendor by default (updateable via composer)
use Nasirkhan\ModuleManager\Modules\Post\Models\Post;
use Nasirkhan\ModuleManager\Modules\Post\Http\Controllers\PostController;
// Or if published to Modules/ for customization:
use Modules\Post\Models\Post;
use Modules\Post\Http\Controllers\PostController;Configuration files can now be published separately from modules.
Views now follow Laravel's native vendor override pattern.
# Update composer dependencies
composer update nasirkhan/module-manager
# Clear all caches
php artisan clear-all# See which modules you have and their status
php artisan module:statusOutput will show:
Module Location Customized Update Strategy
Post vendor (package) ✓ No Updateable via composer
Category Modules/ (custom) ⚠ Yes User owns this
Tag vendor (package) ✓ No Updateable via composer
Menu Modules/ (custom) ⚠ Yes User owns this
For any modules you've customized, check what changed:
php artisan module:diff Post
php artisan module:diff Category
php artisan module:diff Tag
php artisan module:diff MenuReview the differences and decide:
- Merge package updates manually
- Keep your customizations
- Or re-publish and re-apply customizations
If you moved modules from Modules/ to vendor packages:
Find and replace in your codebase:
# Example: Update Post module references
Modules\Post\ → Nasirkhan\ModuleManager\Modules\Post\Or, if you want to keep using custom modules:
# Publish the module to Modules/ directory
php artisan module:publish Post# Publish module-manager configuration
php artisan vendor:publish --tag=module-manager-config
# Review and update config/module-manager.php if needed# Check if packages have new migrations
php artisan module:check-migrations
# Publish new migrations if found
php artisan vendor:publish --tag=post-migrations
php artisan vendor:publish --tag=category-migrations
# Run migrations
php artisan migrate# Reinstall npm packages
npm install
# Rebuild assets
npm run build# Run full test suite
php artisan test
# If tests fail, review error messages and update accordinglyReview and update any custom code that extends module classes:
Example:
// If you extended PostController
// app/Http/Controllers/CustomPostController.php
namespace App\Http\Controllers;
// Update import
use Nasirkhan\ModuleManager\Modules\Post\Http\Controllers\PostController as BaseController;
class CustomPostController extends BaseController
{
// Your customizations
}Impact: High if you have deep integration with modules
What Changed:
- Default module location changed from
Modules/to vendor package - Namespace changed for package modules
- Module autoloading follows Laravel's package pattern
Migration:
// Old way (3.x)
use Modules\Post\Models\Post;
// New way (4.x) - Package modules
use Nasirkhan\ModuleManager\Modules\Post\Models\Post;
// Or publish module and keep old namespace
php artisan module:publish Post
use Modules\Post\Models\Post; // Still works!Impact: Low - Laravel handles this automatically
What Changed:
- Views now use Laravel's native vendor override system
- Package views automatically check
resources/views/vendor/{package}/first
Migration:
# To customize views, publish them
php artisan vendor:publish --tag=post-views
# Edit in: resources/views/vendor/post/index.blade.php
# Laravel automatically uses your versionImpact: Low
What Changed:
- Module configs now use
mergeConfigFrom() - Published configs override package defaults
Migration:
# Publish config to customize
php artisan vendor:publish --tag=post-config
# Edit: config/post.php
# Your values automatically override package defaultsWhat Changed:
- Module service providers auto-register from vendor
- Published modules use existing registration
Action Required:
- None if using default setup
- If customized, ensure providers are registered in
bootstrap/providers.php
What Changed:
- New commands added:
module:publish,module:status,module:diff,module:check-migrations
Action Required:
- None - new functionality is additive
# Run composer dump-autoload
composer dump-autoload
# Clear cache
php artisan clear-all# Clear view cache
php artisan view:clear
# Verify view paths
php artisan about# Ensure package is installed
composer require nasirkhan/module-manager
# Check vendor/nasirkhan/module-manager/src/Modules/ existsIf you need to rollback:
# Restore from git
git reset --hard HEAD~1
# Or restore database backup
# Restore files from backupNote: For upgrades from very old versions (pre-2.x), please consult the project's Git history or contact support.
- Documentation: Check docs/ folder
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Found an issue with this upgrade guide? Submit a PR to improve it!
See CONTRIBUTING.md for guidelines.