Slow applications are not fixed by adding caching everywhere. The first step is measuring where time and resources are actually being spent.
When a Laravel page becomes slow, adding cache everywhere can hide the cause and introduce stale data. I first ask which user action is slow, how often it happens and where its time is spent. A useful optimisation has a measured before and after.
Measure the path a request takes
Separate web-server time, PHP execution, database queries, external API calls and frontend rendering. Look at a representative request under realistic data, not a single empty development database. Record response time, query count and slow queries before changing code. Production monitoring can reveal that only one report or customer segment is affected.
Fix the largest avoidable cost
N+1 relationship queries, missing indexes and fetching too many rows are common causes. Eager loading, pagination and selecting only needed fields can help, but each change should be checked against the query plan and actual response time. A database index that speeds one read may slow frequent writes, so the workload matters.
Slow external services belong behind timeouts and clear failure handling. If an action does not need to finish before the response, a Queue may keep the user experience responsive. It does not make the work disappear; workers and retries still need monitoring.
Cache with an invalidation plan
Cache stable expensive results when their freshness requirement is understood. Define when each entry expires or is invalidated after a write. Caching personalised or permission-sensitive data requires careful keys; otherwise one user may see another user’s result. Framework configuration and route caches are useful deployment tools but cannot rescue a poor query.
- Measure a baseline and a target.
- Optimise the slowest meaningful path first.
- Test correctness as well as speed.
- Watch error rates and resource use after deployment.
Check the result in production conditions
Load tests and monitoring should resemble real traffic and data distribution. A faster median with a worse slow tail may still hurt users. Keep a rollback path for a change that behaves differently under load.
Performance work is diagnosis followed by a small, verified change. The fastest optimisation is often removing unnecessary work rather than adding another infrastructure layer.
An example of a slow dashboard
Suppose a dashboard slows down as orders grow. The initial trace shows hundreds of relationship queries and a report that scans all historical orders. The first change may be eager loading for the visible list and a date-bounded report query with an appropriate index. Only after measuring that result would I decide whether the report needs a cached summary. Starting with a blanket cache would leave the query problem waiting to return.
The same principle applies beyond the database. If an external API consumes most of the request time, improving a local query will not change the experience. Define a timeout, show a useful pending state or move independent work to a job when the workflow allows it.
Avoid moving the bottleneck
A cache can lower database load and increase pressure on memory or invalidation logic. A queue can improve web response time while workers fall behind. A faster query can move the limit to file processing. After each change, watch the system as a whole: latency, errors, throughput, database and worker health.
Performance targets should reflect the user journey. An admin report run once a day has a different acceptable time from a search box used on every page. Prioritise the slow action that costs users time or blocks business, not simply the largest number in a profiling tool.
Keep the measurement and reasoning with the change. Six months later, a teammate should know why a cache exists, what invalidates it and which workload justified the index. That context prevents well-intentioned changes from undoing the optimisation.
I review bottlenecks as part of deployment, performance and scaling work.