~17 seconds to ~1 second without rewriting the workflow.
The visible screen stayed familiar. The data path underneath it changed substantially.
A mature CRM grid had become slow enough to disrupt normal work.
The original path leaned on large database views, derived fields and relationship-heavy retrieval. Those abstractions were convenient when the system was smaller, but the request eventually accumulated several seconds of database work before PHP could even render the grid.
In the observed slow path, one counter/view branch consumed roughly seven seconds and another relationship-heavy branch around hotels consumed roughly nine seconds. The target was therefore not “optimize Blade.” The expensive work happened earlier.
The requirement was strict: preserve the existing filters, default sorting, result shape and workflow. Users should experience a faster screen, not a redesigned feature.
Stop asking one giant view to answer every question on the screen.
The implementation moved the main result set back to the application models and kept expensive counters as separate focused work. Existing filter logic was reused rather than reimplemented.
public function getGridData(array $filters)
{
$query = Record::query()
->select([
'record_id',
'title',
'start_at',
'end_at',
'status_id',
])
->with([
'client',
'owner',
'membersSummary',
]);
$this->applyRecordTypeFilter($query, $filters['type'] ?? null);
$records = $query
->orderBy($this->defaultSortColumn(), 'desc')
->get();
$counters = $this->loadGridCounters(
$records->pluck('record_id')
);
return $this->mergeGridCounters($records, $counters);
}
The excerpt is intentionally simplified and all domain-specific identifiers are generalized. The important implementation decision is real: preserve the caller contract, reuse existing filter behavior, and stop making the broad view carry unrelated aggregation work.
The old path stayed available while the new one proved itself.
Performance rewrites are easy to celebrate and easy to get subtly wrong. The legacy retrieval method was retained during transition so output and behavior could be compared and rollback remained cheap.
Kept existing type/filter logic rather than creating a parallel interpretation of the business rules.
Preserved default sorting and the caller-visible result contract.
Moved the grid away from the view-heavy retrieval path.
Used model relationships where they were a clearer source of truth.
Separated counters from broad grid retrieval rather than forcing one query to do everything.
Kept the previous method available during transition to reduce deployment risk.
The same business screen became roughly an order of magnitude faster.
This example is based on production Laravel performance work performed outside a named NoRewrite client engagement. Employer/client identifiers, model names, field names and method names are removed or generalized. Timings and the architectural change are retained to show the diagnostic and implementation method.