
September 09, 2026
13 min read
By Kokil Thapa | Last reviewed: September 2026
Laravel performance optimization is not one magic switch. It is a stack of small, measurable changes applied in the right order. A booking portal that felt fine at launch can crawl once order history, media uploads, and admin reports grow. I've seen this on production Laravel applications where the code was correct but config, queries, and infrastructure were left at development defaults. This guide walks through 15 Laravel performance optimization techniques that actually ship results—not theoretical micro-optimisations you forget after deploy.
What does Laravel performance optimization cover in a real production stack?
Think in layers. Request handling sits on PHP, the framework bootstrap, your application code, the database, cache, queue workers, and the web server. A slow page is rarely one line of bad code. It is often five acceptable choices that compound.
On client projects I maintain with Deployer 7 and GitLab CI on Ubuntu, the same fixes recur after every major upgrade. Laravel 13.x on PHP 8.3 or 8.5 behaves differently from Laravel 12 on PHP 8.2. Always re-benchmark after a framework bump.
Start with measurement. Without a baseline, you cannot prove a change helped. Use Laravel Debugbar locally, Laravel Pulse in staging, or simple DB::listen() logging for query counts. Record TTFB, query count, and memory before you touch config.
How do you optimize Laravel database queries and Eloquent performance?
Database work is usually the first bottleneck on data-heavy Laravel applications. These five techniques target query count, row volume, and index use.
Technique 1: Fix N+1 queries with eager loading
The classic N+1 problem loads related models inside a loop. One query becomes hundreds. Use with() for relationships you know you need.
/* Bad: N+1 on a booking index */
$bookings = Booking::latest()->paginate(20);
foreach ($bookings as $booking) {
echo $booking->customer->name;
}
/* Good: two queries total */
$bookings = Booking::with(['customer', 'tour'])
->latest()
->paginate(20); Install barryvdh/laravel-debugbar in local only. Watch the query tab on list pages. Anything above 10–15 queries on a simple index deserves investigation.
Technique 2: Add indexes that match real WHERE and JOIN clauses
Missing indexes show up once tables pass a few hundred thousand rows. Check slow query logs on MySQL 8.4 LTS or MySQL 9.7. Add composite indexes for filters you combine often.
Schema::table('bookings', function (Blueprint $table) {
$table->index(['status', 'created_at']);
$table->index('customer_id');
}); Do not index every column. Each index slows writes. Profile with EXPLAIN before and after.
Technique 3: Select only the columns you display
SELECT * pulls large text and JSON fields you never render. Narrow the select list on list views.
Booking::select(['id', 'reference', 'status', 'created_at'])
->with(['customer:id,name'])
->latest()
->paginate(20); Eloquent needs the parent's key for eager loading. Include foreign keys in both select lists.
Technique 4: Chunk or cursor large exports instead of loading all rows
Spreadsheet exports and report generation should never call Model::all(). Use chunkById() or lazy() and stream output.
Booking::where('status', 'confirmed')
->chunkById(500, function ($bookings) use ($writer) {
foreach ($bookings as $booking) {
$writer->addRow($booking->toExportArray());
}
}); Pair this with a queued job so the HTTP request returns immediately.
Technique 5: Cache expensive aggregates with tagged cache invalidation
Dashboard totals that scan millions of rows belong in cache, not on every page load. Use Redis tags when your driver supports them.
$stats = Cache::tags(['bookings'])->remember('dashboard.stats', 300, function () {
return [
'confirmed' => Booking::where('status', 'confirmed')->count(),
'revenue' => Payment::whereMonth('created_at', now()->month)->sum('amount'),
];
}); Flush the tag when a booking or payment changes. Stale dashboard numbers erode trust faster than a one-second delay.
Which Laravel caching strategies deliver the biggest performance gains?
Caching is where Laravel performance optimization: 15 Techniques That Work pays off fastest. These five changes require minutes to deploy and seconds to verify.
Technique 6: Run artisan cache commands on every production deploy
Laravel compiles routes, config, views, and events into flat files. Skipping this step leaves the framework parsing PHP arrays on every request.
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache Add these to your Deployer recipe after composer install. Reload PHP-FPM so OPcache picks up changed files. Never run config:cache if your config closures depend on runtime env() calls outside config files—that breaks production silently.
Technique 7: Tune PHP OPcache for production workloads
OPcache keeps compiled bytecode in memory. Default settings on Ubuntu are conservative. Raise memory and validate timestamps only when you need instant deploy reflection.
; /etc/php/8.5/fpm/conf.d/10-opcache.ini
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0
opcache.jit=1255
opcache.jit_buffer_size=128M With validate_timestamps=0, you must reload PHP-FPM after deploy. That is normal on servers I manage. See the official PHP OPcache documentation for JIT trade-offs on CPU-bound apps.
Technique 8: Move cache, sessions, and queues to Redis 8.10
File and database cache drivers work on small sites. They fall apart under concurrent traffic. Redis handles cache, sessions, and queues from one service.
CACHE_STORE=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis
REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379 Run at least one dedicated queue worker via Supervisor. A backlog of unprocessed jobs eventually slows user-facing flows that dispatch them synchronously by mistake.
| Driver | Best for | Throughput | Ops complexity |
|---|---|---|---|
| File | Local dev, tiny sites | Low | Minimal |
| Database | Shared hosting without Redis | Medium-low | Low |
| Redis | Production Laravel 13 apps | High | Moderate |
| Memcached 1.6.x | Cache-only, multi-server | High | Moderate |
Technique 9: Cache full HTTP responses for anonymous pages
Public blog posts, landing pages, and legal guides rarely change per visitor. Response caching skips controller work entirely.
/* routes/web.php */
Route::middleware('cache.headers:public;max_age=3600')->group(function () {
Route::get('/guides/{slug}', [GuideController::class, 'show'])
->middleware('cacheResponse:3600');
}); Spatie's response cache package is a solid choice. Invalidate on model update events. Never cache authenticated dashboards without user-specific cache keys.
Technique 10: Offload slow tasks to queued jobs
Email, PDF generation, image processing, and third-party API calls do not belong in the request cycle. Dispatch a job and return a 202 or redirect.
GenerateInvoicePdf::dispatch($order)->onQueue('documents');
/* Job class */
public function handle(): void
{
$pdf = Pdf::loadView('invoices.show', ['order' => $this->order]);
Storage::put($this->path, $pdf->output());
} On trek booking systems with supplier CRM flows, queue workers handle itinerary PDFs while the user sees a confirmation screen immediately.
How do you optimize Laravel frontend assets and HTTP delivery?
Backend tuning means little if each page loads 2 MB of JavaScript and unoptimised images. These three techniques target the browser and the edge.
Technique 11: Ship a production Vite 8.x build with hashed filenames
Development assets are unminified and unbundled. Production must run npm run build and commit or deploy the public/build manifest.
/* vite.config.js — typical Laravel 13 setup */
export default defineConfig({
plugins: [
laravel({
input: ['resources/css/app.css', 'resources/js/app.js'],
refresh: true,
}),
],
build: {
rollupOptions: {
output: { manualChunks: { vendor: ['axios', 'lodash'] } },
},
},
}); Enable Brotli or gzip at Nginx or Apache. Long cache headers on hashed assets are safe because the filename changes when content changes.
Technique 12: Optimise and lazy-load images in the media pipeline
Upload directories on legal-tech portals fill with scanned PDFs and high-resolution photos. Generate responsive variants at upload time. Lazy-load below-the-fold images in Blade.
<img
class="lazyload img-fluid"
data-src="{{ $media->getUrl('webp-large') }}"
alt="{{ $article->title }}"
width="800"
height="450"
loading="lazy"
> Spatie Media Library with WebP conversions is a pattern I use regularly. Pair image work with sensible max upload limits in PHP and Nginx.
Technique 13: Put static assets and public pages behind a CDN
Serve /build/* and user uploads from a CDN subdomain. Enable HTTP/2 or HTTP/3 at the edge. Set Cache-Control headers explicitly in middleware or server config.
/* Nginx snippet for hashed Vite assets */
location /build/ {
expires 1y;
add_header Cache-Control "public, immutable";
try_files $uri =404;
} For Nepal-hosted apps with global visitors—florist eCommerce is a common case—CDN latency drops more than any PHP tweak. See our international WooCommerce and Laravel storefront work for multi-region delivery patterns.
What production server and Laravel configuration changes speed up apps in 2026?
The last five techniques live outside app/. They matter as much as Eloquent tuning on a live server under load.
Technique 14: Disable debug tooling and tighten PHP-FPM pools
Debugbar, Telescope, and Clockwork belong in local and staging only. Accidentally leaving them enabled leaks queries and doubles response time.
/* config/app.php — bind via .env */
'debug' => (bool) env('APP_DEBUG', false),
/* composer.json — move debugbar to require-dev */
"require-dev": {
"barryvdh/laravel-debugbar": "^3.14"
} Size PHP-FPM pools to RAM. A 2 GB VPS with 50 max children will swap and die. Start with pm.max_children = 10 on small instances and watch memory per worker with ps or Pulse.
Technique 15: Consider Laravel Octane for high-concurrency APIs
Octane keeps the application booted in memory using Swoole or RoadRunner. It suits stateless API endpoints with careful memory management. It is not a default choice for every CRUD app.
composer require laravel/octane
php artisan octane:install --server=swoole
php artisan octane:start --workers=4 --max-requests=500 Avoid storing request-specific state in singletons. Reset connections between requests. Read the Laravel Octane documentation before enabling on a document-upload portal with large in-memory buffers.
Bonus checks that prevent regressions after deploy
These are not separate headline techniques but they save hours in production debugging.
- Run
composer install --no-dev --optimize-autoloaderon deploy with Composer 2.10. - Set
APP_ENV=productionandLOG_LEVEL=warningto cut disk I/O from verbose logs. - Use database connection pooling or read replicas only when metrics prove write contention—not prematurely.
- Schedule
php artisan queue:restartafter deploy so workers load new code. - Monitor queue depth, slow queries, and 502 rates with Laravel Pulse or an external APM.
Validate JSON API payloads during development with our JSON formatter tool before load tests hit malformed responses. For regex-heavy validation rules, the regex tester catches catastrophic backtracking early.
On sister sites sharing one EC2 host—notary portals and translation services among them—stale cron paths and missed FPM reloads cause more post-deploy slowness than bad algorithms. Treat performance steps as part of CI, not a manual checklist.
If you need a structured audit before a busy season—Dashain eCommerce spikes are predictable—testing and optimization services should cover load profiles, not just Lighthouse scores. Budget roughly Rs 25,000–80,000 (~USD 185–590) for a focused Laravel audit in Nepal, depending on app size and staging access.
For ongoing work after launch, support and maintenance retainers catch query regressions when new features land. API-heavy integrations need separate load testing because Octane and queue tuning interact with webhook throughput.
Founders comparing build options can review Laravel legal-tech portals in the portfolio and client portal implementations that balance document uploads with page speed. Customer reviews mention on-time delivery; performance was part of that because slow admin panels block staff daily.
Read more engineering notes on the blog. Learn about the author on the about page or the homepage. Custom Laravel builds start from custom software development and web development services.
Key Takeaways
- Measure query count and TTFB before changing anything—optimization without baselines is guesswork.
- Fix N+1 queries, add matching indexes, and cache expensive aggregates before chasing exotic tools.
- Run
config:cache,route:cache, andview:cacheon every production deploy, then reload PHP-FPM. - Move cache, sessions, and queues to Redis; keep slow IO in background jobs.
- Build frontend assets with Vite, optimise images, and serve static files through a CDN with long cache headers.
- Disable debug packages in production and size PHP-FPM pools to available RAM on the server.
People Also Ask
How much faster can Laravel performance optimization make my app?
Results vary by starting point. A site with N+1 queries, no route cache, and file-based sessions often sees 40–70% TTFB improvement from the first six techniques alone. Apps already on Redis with cached routes may gain only 10–15% unless database indexes or asset delivery are the bottleneck.
Is Redis required for Laravel performance optimization in 2026?
Not strictly required, but strongly recommended for any app with more than a few concurrent users or background jobs. Redis 8.10 handles cache, sessions, and queues from one service. Database and file drivers become contention points under load.
Should I use Laravel Octane for every project?
No. Octane fits high-throughput, mostly stateless APIs when you understand memory lifecycle and connection reset rules. Traditional PHP-FPM plus good caching is the right default for admin-heavy CRUD apps and document upload portals.
When should I hire someone for Laravel performance optimization?
Bring in help when slow queries persist after eager loading and indexes, when deploys cause downtime, or when you lack staging that mirrors production traffic. A senior engineer can usually identify the top three bottlenecks in a day if logs and database access are available.
Apply these 15 techniques and measure every change
Laravel performance optimization: 15 Techniques That Work is a checklist, not a one-time sprint. Cache on deploy, watch queries in staging, queue anything slower than 200 ms, and keep OPcache and PHP-FPM aligned with your server RAM. The wins compound when the whole stack—not just one controller—gets attention.
Need a production audit, deploy pipeline fix, or Redis migration on Laravel 12 or 13? Contact us with your stack details and current TTFB numbers. We will tell you honestly which of the 15 techniques matter most for your app.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

