Fred CastroAfter 10+ years building scalable web applications with Laravel for everything from startups to...
After 10+ years building scalable web applications with Laravel for everything from startups to government systems, I've learned that performance optimization isn't about premature optimization—it's about knowing which battles to fight.
Currently leading development for a federal government system (CAPES), I've had to optimize Laravel apps handling thousands of concurrent users. Here are the 10 most impactful performance tips I wish I knew when I started.
The #1 performance killer I see in Laravel codebases:
// BAD: N+1 queries
$posts = Post::all();
foreach ($posts as $post) {
echo $post->user->name; // Query fired for EACH post
}
// GOOD: 2 queries total
$posts = Post::with('user')->get();
foreach ($posts as $post) {
echo $post->user->name;
}
Impact: Reduced query count from 1,001 to 2 queries in a real project.
Add indexes to columns you filter/join on:
Schema::table('posts', function (Blueprint $table) {
$table->index('user_id');
$table->index('status');
$table->index(['category_id', 'published_at']); // Composite index
});
Pro tip: Use EXPLAIN in MySQL to identify missing indexes.
// Cache database queries
$users = Cache::remember('active_users', 3600, function () {
return User::where('active', true)->get();
});
// Cache computed values
$stats = Cache::remember('dashboard_stats', 600, function () {
return [
'total_users' => User::count(),
'active_sessions' => Session::where('active', true)->count(),
];
});
In production: This reduced our dashboard load time from 2.3s to 180ms.
// config/database.php
'redis' => [
'client' => 'phpredis', // Use phpredis extension, not predis
'cluster' => false,
'default' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => 0,
],
],
Why Redis? Memory-based storage = 10-100x faster than database sessions.
// BAD: Fetches all columns
$users = User::all();
// GOOD: Select specific columns
$users = User::select('id', 'name', 'email')->get();
// EVEN BETTER: Use pluck for single column
$emails = User::pluck('email');
Don't make users wait for emails, notifications, or file processing:
// Dispatch to queue
ProcessVideoUpload::dispatch($video);
SendWelcomeEmail::dispatch($user);
// Chain jobs
ProcessOrder::withChain([
new SendInvoice($order),
new UpdateInventory($order),
])->dispatch($order);
Result: Page response time dropped from 4s to 300ms.
composer dump-autoload --optimize
composer install --optimize-autoloader --no-dev
In production: Always run with optimization flags.
; php.ini
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.validate_timestamps=0 # Disable in production
opcache.revalidate_freq=0
Impact: 30-50% performance boost for free.
// BAD: Loads 100k records into memory
User::where('active', true)->get()->each(function ($user) {
// Process user
});
// GOOD: Process in chunks
User::where('active', true)->chunk(200, function ($users) {
foreach ($users as $user) {
// Process user
}
});
Install in development to identify bottlenecks:
composer require laravel/telescope --dev
composer require laravel/horizon
Telescope shows you:
php artisan config:cache
php artisan route:cache
php artisan view:cache
After years of optimization, here's what I recommend:
Performance optimization is a journey, not a destination. Start with the low-hanging fruit (eager loading, indexing, caching) and measure the impact.
In my work on the CAPES federal system, these optimizations reduced response times from 3-5 seconds to under 200ms, handling thousands of concurrent users smoothly.
What's your #1 Laravel performance tip? Drop it in the comments!
Building scalable Laravel apps for 10+ years | Currently: Senior PHP/Laravel Developer at CAPES | Available for consulting and architecture reviews