If you’ve been watching the PHP ecosystem over the past few months, you’ve probably noticed the buzz around running Laravel 12 on PHP 8.4. But how much of it is real, and how much is hype? In this post, we’ll cut through the noise with actual benchmark templates, common upgrade pitfalls, and a rollout strategy you can use in production.
Why This Combo Is Trending Now
Laravel 12 officially requires PHP 8.2 as a minimum, but it’s optimized to take advantage of PHP 8.4 features under the hood. Meanwhile, PHP 8.4 shipped with meaningful performance improvements in the JIT compiler, property hooks, and asymmetric visibility — features Laravel 12’s internals leverage directly.
The timing matters too. PHP 8.3 reached its active support window, and teams that skipped 8.3 are now jumping straight to 8.4. Laravel 12’s release aligned with this wave, making the dual upgrade a natural move for teams planning their spring infrastructure work.
There’s also a practical driver: PHP 8.4’s lazy objects and improved JIT warmup behavior reduce cold-start penalties, which is especially relevant for containerized Laravel deployments where pods scale frequently.
Where You’ll Likely See Gains First
Not every part of your application will speed up equally. Based on community reports and our own testing, here’s where the improvements tend to show up first:
Serialization and deserialization. PHP 8.4’s internal optimizations to json_encode/json_decode and object hydration translate directly to faster API response times in Laravel, especially if you’re using API Resources or heavy Eloquent serialization.
Queue throughput. Laravel’s queue workers benefit from PHP 8.4’s reduced memory overhead per process. If you’re running multiple workers on a single machine, you’ll notice lower baseline memory usage, which means you can run more workers or handle larger payloads before hitting limits.
Route resolution. Laravel 12 reworked its route matching internals. Combined with PHP 8.4’s faster string operations, applications with large route files (200+ routes) will see measurably faster route resolution.
Blade compilation. First-render times for Blade templates drop slightly thanks to PHP 8.4’s improved file I/O and opcache preloading behavior. This is most noticeable in applications that render many partials per request.
A Practical Benchmark Template
Before upgrading production, measure your own baselines. Here’s a template you can adapt.
Scenario A: API Throughput
Test a representative API endpoint that hits your database and returns a JSON response. This captures serialization, Eloquent, and routing performance in one measurement.
# Using wrk for HTTP benchmarking
# Run against your staging environment on PHP 8.3, then again on PHP 8.4
# Baseline (PHP 8.3 + Laravel 11 or 12)
wrk -t4 -c50 -d30s http://staging.yourapp.test/api/v1/orders
# After upgrade (PHP 8.4 + Laravel 12)
wrk -t4 -c50 -d30s http://staging-84.yourapp.test/api/v1/orders
# Record: requests/sec, avg latency, p99 latency, transfer/secTypical improvement range: 5–12% higher requests/sec, with the biggest gains on endpoints that serialize large collections.
Scenario B: Queue Throughput
Measure how many jobs your queue workers process per minute under sustained load.
# Dispatch 10,000 test jobs
php artisan benchmark:dispatch-jobs --count=10000
# Monitor processing rate
php artisan queue:work --max-jobs=10000 --verbose 2>&1 | \
tail -1 # Note the total elapsed time
# Compare: jobs processed per minute on PHP 8.3 vs 8.4Typical improvement range: 8–15% more jobs/minute, primarily from reduced per-job memory allocation overhead.
Scenario C: CLI Task
Benchmark a representative Artisan command — something like a data import or report generation.
# Time a CLI task that exercises your models and business logic
time php artisan reports:generate-monthly --month=2026-02
# Run 5 iterations on each PHP version, compare averages
# Also monitor peak memory: php -d memory_limit=512M artisan ...Typical improvement range: 3–8% faster execution, with more pronounced gains on memory-intensive tasks.
Common Upgrade Blockers and Fixes
Composer Constraints
Many packages pin their PHP version ceiling. You’ll hit this first.
composer why-not php 8.4This command shows which packages are blocking the upgrade. Common offenders include older versions of phpunit/phpunit, fakerphp/faker, and niche packages that haven’t updated their composer.json. In most cases, the package works fine on 8.4 — the constraint is just conservative. Check the package’s GitHub issues before deciding to fork or find an alternative.
Legacy Dynamic Property Patterns
PHP 8.2 deprecated dynamic properties, and PHP 8.4 enforces this more aggressively in certain contexts. If you have older code that sets properties on objects without declaring them:
// This will trigger deprecation notices on 8.4
$user->temporaryFlag = true;
// Fix: declare the property or use AllowDynamicProperties
#[\AllowDynamicProperties]
class LegacyService
{
// ...
}
// Better fix: declare the property explicitly
class LegacyService
{
public bool $temporaryFlag = false;
}Run your test suite with deprecation notices promoted to errors to catch these early:
php -d error_reporting=E_ALL artisan testQueue Worker Drift
This is a subtle one. If you upgrade PHP on your web servers but forget your queue workers, you end up with workers running on the old PHP version processing jobs dispatched by the new version. This usually works, but serialized closures and some Laravel-specific serialization formats can break across PHP versions.
Fix: Always upgrade queue workers and web servers together. If you’re using Horizon, restart all Horizon processes after the PHP upgrade. If you’re using Supervisor, make sure the command directive points to the correct PHP binary:
[program:laravel-worker]
command=/usr/bin/php8.4 /var/www/app/artisan queue:workSafe Rollout Strategy
Don’t flip the switch on all production traffic at once. Here’s a four-phase approach:
Phase 1: Shadow
Deploy your application on PHP 8.4 alongside your existing PHP 8.3 stack. Mirror a percentage of production traffic to the 8.4 instances but don’t serve responses from them. Compare error logs and response times.
Duration: 2–3 days.
Phase 2: Canary
Route 5–10% of real production traffic to the PHP 8.4 instances. Monitor error rates, response times, and queue processing metrics. Pay special attention to edge cases: file uploads, long-running requests, WebSocket connections if applicable.
Duration: 3–5 days.
Phase 3: Observe
Increase traffic to 50%. At this point, you’re looking for performance degradation under load, memory leaks that only appear over hours of uptime, and any subtle behavioral differences.
Duration: 2–3 days.
Phase 4: Full Rollout
Move all traffic to PHP 8.4. Keep the PHP 8.3 instances available for a quick rollback for at least one week.
Duration: Ongoing, with rollback capability for 7 days.
What Not to Expect
It’s worth being honest about the limitations:
-
Don’t expect a 2x speedup. The improvements are real but incremental. A 5–15% improvement across various metrics is significant at scale, but it won’t transform a slow application into a fast one. If your app is slow, the bottleneck is almost certainly in your application code or database queries, not the PHP runtime.
-
Don’t expect zero breaking changes. Even with excellent test coverage, you’ll likely find a handful of deprecation warnings or behavioral changes. Budget time for these.
-
Don’t expect automatic adoption of new features. PHP 8.4 introduces property hooks, asymmetric visibility, and lazy objects. Laravel 12 uses some of these internally, but your application code won’t benefit from them unless you consciously adopt them. The performance gains come from the engine improvements, not from new syntax you haven’t written yet.
-
Don’t expect identical behavior in all extensions. Some PECL extensions lag behind major PHP releases. Check that your critical extensions (Redis, MongoDB, gRPC, etc.) have stable 8.4-compatible releases before upgrading.
Final Takeaway
The Laravel 12 + PHP 8.4 combination delivers genuine, measurable improvements — particularly in API serialization, queue throughput, and memory efficiency. But the key word is measurable. Before upgrading, establish your baselines using the benchmark templates above. After upgrading, measure again and compare.
The upgrade itself is straightforward for most applications, but watch for Composer constraints, dynamic property deprecations, and queue worker version drift. Use a phased rollout, and give yourself a clear rollback path.
The best time to upgrade is when your test suite is green, your team has capacity to monitor the rollout, and you’ve run the benchmarks on staging. Skip the hype cycle — let your own numbers tell the story.