Laravel 12 continues the framework's evolution toward a leaner, more streamlined application structure that began with Laravel 11. If you are deploying a Laravel 12 application for the first time, or upgrading an existing application, several structural changes directly affect your deployment pipeline, server configuration, and operational practices.
This guide covers every deployment-relevant change in Laravel 12, explains why it matters for your production environment, and shows how Deploynix handles each change. Whether you are deploying a fresh Laravel 12 application or migrating from an earlier version, this post will ensure your deployment pipeline is correct and complete.
The Streamlined Directory Structure
The most visible change in Laravel's modern structure (carried forward from Laravel 11 into 12) is the simplified directory layout. Several files and directories that existed in earlier versions are no longer present, and understanding what moved where is essential for deployment.
No More app/Http/Kernel.php
In earlier Laravel versions, app/Http/Kernel.php was the central registry for middleware. You defined global middleware, middleware groups, and middleware aliases there. Every deployment guide told you to check this file when troubleshooting middleware issues.
In Laravel 12, this file does not exist. Middleware is configured declaratively in bootstrap/app.php using the fluent Application::configure()->withMiddleware() method:
->withMiddleware(function (Middleware $middleware) {
$middleware->alias([
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
]);
})
For deployment, this means your deployment scripts or code reviews that reference app/Http/Kernel.php need to be updated. If you have custom middleware that needs to be registered, it goes in bootstrap/app.php, not in a Kernel class.
No More app/Console/Kernel.php
The console kernel has also been removed. Console commands in app/Console/Commands/ are automatically discovered and registered. You do not need to manually register them anywhere.
Scheduled tasks that previously lived in app/Console/Kernel.php's schedule() method now live in routes/console.php or are configured in bootstrap/app.php. If your deployment pipeline includes scheduled tasks (and it should, for things like queue monitoring, cache cleanup, and database backups), verify they are defined in the correct location.
On Deploynix, cron job management works the same regardless of where your scheduled tasks are defined. Deploynix's cron configuration calls php artisan schedule:run every minute, and Laravel discovers and executes your scheduled tasks from wherever they are registered.
bootstrap/app.php Is the Central Configuration Hub
The bootstrap/app.php file is now the single location for three critical concerns:
- Middleware registration: Global middleware, middleware groups, and middleware aliases
- Exception handling: Custom exception rendering, reporting, and handling
- Routing: Registration of route files and route-level middleware
This file is loaded on every request, so its correctness is essential. A syntax error or misconfiguration here will take your entire application down. Include bootstrap/app.php in your code review checklist before every deployment.
bootstrap/providers.php
Application-specific service providers are registered in bootstrap/providers.php instead of the old config/app.php providers array. This file returns a simple array of provider classes:
return [
App\Providers\AppServiceProvider::class,
];
If your application uses custom service providers (and most do), verify they are listed here. A missing service provider in this file means that provider's boot and register methods never execute, which can cause subtle failures that are hard to debug in production.
Deployment Pipeline Changes
Config Caching
The php artisan config:cache command still works as expected, but it now caches configuration from the new file structure. Make sure your deploy script include this command after every deployment:
php artisan config:cache
One important behavior to remember: once configuration is cached, Laravel does not read .env files or individual config files. If you update an environment variable on your Deploynix server, you need to re-run php artisan config:cache for the change to take effect. Deploynix's deployment process handles this, but if you manually update an environment variable between deployments, clear the config cache with php artisan config:clear or wait for the next deployment.
Route Caching
Route caching is unchanged in its command (php artisan route:cache) but there is a nuance worth noting. Since middleware is now defined in bootstrap/app.php, the route cache includes the middleware configuration from that file. If you change middleware configuration, you must regenerate the route cache.
Include in your Deploynix deploy script:
php artisan route:cache
Event Caching
The php artisan event:cache command works with the new automatic event discovery. Laravel 12 auto-discovers event listeners based on method signatures without requiring manual registration. The event cache captures these discovered mappings.
Migration Safety
Laravel 12 has an important database migration behavior: when modifying a column, the migration must include all attributes previously defined on that column. Otherwise, they will be dropped. This is not new to Laravel 12, but it is worth emphasizing because it catches people during deployment.
For example, if you have a column defined as string('name')->nullable()->default('guest') and you create a migration that does $table->string('name')->nullable()->change(), the default('guest') will be removed. The migration must include $table->string('name')->nullable()->default('guest')->change() to preserve all attributes.
Always review your migrations carefully before running them in production. Use Deploynix's deploy script to run php artisan migrate --force as part of your deployment pipeline.
PHP Requirements
Laravel 12 requires PHP 8.2 or higher. Deploynix supports multiple PHP versions and allows you to select the PHP version during server provisioning or change it afterward.
If you are upgrading from an earlier Laravel version, verify that your Deploynix server is running PHP 8.2 or later. PHP 8.4 is recommended for the best performance and access to the latest language features including property hooks and asymmetric visibility.
Check your composer.json for a require.php constraint that matches your server's PHP version. A mismatch will cause composer install to fail during deployment.
Octane Compatibility
Laravel 12 works fully with Laravel Octane for high-performance deployments. Deploynix supports all three Octane drivers: FrankenPHP, Swoole, and RoadRunner.
If you are using Octane, the streamlined application structure has some implications. Since the application boots once and stays in memory, changes to bootstrap/app.php (middleware, exception handling, routing) only take effect when the Octane server restarts. Deploynix's deployment process includes restarting Octane workers, but be aware of this during development and debugging.
Octane's warm application model means singleton services persist across requests. The removal of app/Http/Kernel.php does not affect this behavior, but it is worth verifying that any custom middleware you configure in bootstrap/app.php is stateless and does not accumulate data across requests.
Queue Worker Changes
Queue workers in Laravel 12 work the same way from a deployment perspective. The php artisan queue:work command is unchanged. However, if your queue workers depend on scheduled task configuration (for example, if you have a scheduled command that monitors queue health), verify that the schedule is correctly defined in routes/console.php.
On Deploynix, queue workers run as daemons that are automatically restarted after deployment. The php artisan queue:restart command is included in the deployment process to gracefully restart workers so they pick up new code.
If you use Deploynix's dedicated Worker servers, no changes are needed for Laravel 12. The worker daemon configuration remains the same.
Testing in Production
Laravel 12 ships with Pest 4, which includes browser testing capabilities. While you would not run browser tests in production, Pest 4's smoke testing feature can be valuable as a post-deployment verification step. You can write smoke tests that visit critical pages and verify they load without JavaScript errors.
Consider adding a smoke test step to your Deploynix deploy script that runs against your production URL:
php artisan test --filter=Smoke
This catches rendering errors, missing assets, and configuration problems that unit tests would not detect.
Environment Variable Changes
Laravel 12 does not introduce new required environment variables, but the emphasis on bootstrap/app.php as the configuration hub means you should be especially careful about the distinction between environment variables and configuration.
The rule remains the same: never use env() outside of config files. Always use config() to access configuration values in your application code. With config caching enabled (which it should be in production), env() calls outside of config files will return null because the .env file is not loaded when a cached config exists.
Review your codebase for env() calls outside of config/ files. This is a common source of bugs that only manifest in production where config caching is enabled.
Eager Loading Improvements
Laravel 12 includes native support for limiting eagerly loaded records without external packages. You can now write:
$users = User::with(['posts' => function ($query) {
$query->latest()->limit(10);
}])->get();
This is relevant to deployment because it means you can remove packages that previously provided this functionality. Fewer dependencies mean faster composer install during deployment, a smaller vendor directory, and fewer potential version conflicts.
Upgrading Existing Applications
If you are upgrading an existing application to Laravel 12 and deploying it on Deploynix, here is the deployment-specific checklist:
- Verify PHP version. Ensure your Deploynix server runs PHP 8.2+.
- Migrate kernel configuration. Move middleware from
app/Http/Kernel.phptobootstrap/app.php. Move schedule fromapp/Console/Kernel.phptoroutes/console.php. - Update providers. Move provider registration from
config/app.phptobootstrap/providers.php. - Test config caching. Run
php artisan config:cachelocally and verify your application works correctly. - Test route caching. Run
php artisan route:cachelocally and verify all routes resolve correctly. - Review migrations. Ensure all column modifications include all existing attributes.
- Update deploy script. Verify your Deploynix deploy script includes all cache commands.
- Test queue workers. Verify queue workers start correctly with the new application structure.
- Run your test suite. All tests should pass before deploying.
- Deploy to staging first. Use a Deploynix staging site to verify the upgrade works before touching production.
Deploynix Full Support
Deploynix fully supports Laravel 12 applications out of the box. The platform's provisioning process installs the correct PHP version, configures Nginx appropriately, and sets up the deployment pipeline with all the cache commands your Laravel 12 application needs.
The deploy script template for Laravel 12 includes:
composer install --optimize-autoloader --no-dev
php artisan migrate --force
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache
Zero-downtime deployment works identically for Laravel 12. The symlink-based deployment strategy is framework-agnostic and handles the new directory structure without any special configuration.
Scheduled deployments, rollback, custom deploy scripts, and all other Deploynix deployment features work with Laravel 12 without modification.
Conclusion
Laravel 12's deployment changes are evolutionary, not revolutionary. The framework continues to streamline its structure, removing boilerplate files and centralizing configuration. For deployment purposes, the key changes are the location of middleware configuration (now in bootstrap/app.php), the location of scheduled tasks (now in routes/console.php), and the provider registration (now in bootstrap/providers.php).
If you are deploying a fresh Laravel 12 application on Deploynix, everything works out of the box. If you are upgrading, follow the checklist above and deploy to staging first. The changes are straightforward but touching middleware, scheduling, and provider registration simultaneously means there are multiple potential failure points.
Top comments (0)