A faster Laravel website usually comes from several small decisions working together. Start with evidence, remove repeated work, reduce unnecessary data and move slow tasks away from the response.
01
Start with the work the application should not be doing
A slow Laravel website rarely has one dramatic fault. More often, the delay is spread across repeated database queries, unnecessary data, work being completed inside the request and production settings that were never properly finished.
That is good news. Useful performance improvements do not always require a rewrite, a new hosting platform or a clever new package. They often come from removing work the application did not need to do in the first place.
Imagine a customer portal dashboard. It loads the customer, recent jobs, uploaded documents, several counts and the name of the person responsible for each job. When somebody approves a record, the same request generates a PDF, sends an email and updates an external system. The page works, but every extra record makes it feel slower.
The ten ideas below turn that vague complaint into a more controlled investigation. They are not a sequence every application must follow. Start with evidence, choose the change that addresses the measured delay, then measure again.
| What you notice | A useful first check | A likely direction |
|---|---|---|
| A page gets slower as more rows appear | Query count and data volume | Eager loading, selecting fields and pagination |
| The first request is much slower after deployment | Framework boot and PHP runtime | Laravel optimisation caches and OPcache |
| Saving a form waits on email or document work | Request timeline | Queue background work |
| The same dashboard totals are calculated repeatedly | Cache hit rate and query time | Cache stable results with clear invalidation |
| Local development is quick but production is inconsistent | Production logs, workers and infrastructure | Monitor the real environment and reload services correctly |
02
1. Measure the slow request before changing it
The first optimisation is refusing to guess.
Record which route is slow, how long it takes and whether the delay sits in PHP, the database, an external service or the browser. Laravel can listen to individual queries and can also act when the total database time during a request crosses a threshold. Laravel Pulse, Telescope, application logs and a full profiler answer different parts of the same question.
For a small code comparison, Laravel's Benchmark class is useful. For a whole customer journey, look at the request, database, queue and browser together. A method that becomes twice as fast may make no visible difference when the request is waiting 800 milliseconds for an external API.
Capture a baseline before the change. Use representative data and repeat the same journey afterwards. Otherwise, a warm cache or a quiet development machine can make an unrelated edit look like a victory.
03
2. Build Laravel's optimisation caches during deployment
Laravel reads configuration, discovers events, registers routes and compiles Blade views as it runs. In production, much of that preparation can be performed once during deployment.
Laravel's php artisan optimize command caches configuration, event mappings, routes and views. The individual commands remain available when a deployment needs finer control. This is simple work for the framework to avoid on every request, particularly in a large application with many routes and templates.
Make optimisation part of the release process rather than an occasional command somebody remembers to run. Clear or rebuild the caches when configuration or application code changes. Also keep calls to env() inside configuration files because a cached configuration means Laravel will not load the .env file in the normal way.
This is a reliable production improvement, but it will not rescue a page making 300 database queries. Framework boot time and application behaviour are separate problems.
04
3. Keep production configuration genuinely production ready
Set APP_DEBUG to false in production. Laravel's documentation treats this as a security requirement because debug output can expose sensitive configuration. It also prevents production from doing the extra work needed to build detailed development error pages.
Check the rest of the environment at the same time. Logging should be useful without writing an enormous debug record for every normal request. Development tools should not be enabled carelessly. The cache, session and queue drivers should match the way the application is expected to operate.
Do not turn logging off just to make a graph look better. A fast application that cannot explain a failure is not production ready. The aim is purposeful operational evidence, not silence.
05
4. Remove N+1 queries with deliberate eager loading
An N+1 query appears when the application fetches a list and then runs another query for a relationship on every item. A dashboard with 100 jobs can quietly make one query for the jobs and 100 more for their owners.
Eloquent's eager loading uses with() to fetch the required relationships in a small number of queries. loadMissing() can add a relationship later without loading it twice. Laravel can also prevent lazy loading outside production so accidental relationship queries become visible during development and testing.
Eager loading everything is not the answer. Pulling five deep relationships into every request can move the problem from query count to memory and data volume. Load the relationships this screen or API response actually needs, and constrain them when only a subset matters.
The useful measurement is not simply fewer queries. It is fewer unnecessary queries while returning the same correct result.
06
5. Ask the database for less data
Model::all() is convenient, but convenience becomes expensive when a table grows. If a list only displays an identifier, name, status and updated date, there is no benefit in retrieving a large notes field, private metadata and every other column.
Select the fields the operation needs. Use withCount() when the screen needs a number rather than every related model. Paginate lists that a person reads one screen at a time. Use chunking or lazy iteration for large background operations so the application does not load an entire table into memory.
This also applies to JSON responses. A front end cannot render data it never asked for any faster simply because the server sent it anyway.
Be careful when selecting relationship fields. Eloquent still needs the relevant primary and foreign keys to connect the records correctly. Smaller payloads are useful only when they remain complete enough for the operation.
07
6. Give frequent queries suitable indexes
Application code can look tidy while the database repeatedly scans thousands of rows to find a small result. Indexes help the database locate and order records, particularly for columns used regularly in filters, joins and sorting.
Start with a slow query and inspect its execution plan. If a portal regularly finds open jobs by customer and orders them by due date, a suitable compound index may be more useful than several separate indexes. The right answer depends on the database, the query and the shape of the data.
Do not add an index to every column. Indexes consume storage and must be maintained when rows change, so heavy write activity can become slower. They also do not fix a query asking for far more information than the page needs.
Treat schema changes like application changes. Test them with realistic volume, review locking and deployment implications, and keep them in migrations so every environment receives the same structure.
08
7. Cache stable work with an expiry and an invalidation plan
Some results are expensive to calculate but do not need to be rebuilt for every visitor. Dashboard totals, permissions derived from stable rules and slow reference data can be good cache candidates.
Laravel's Cache::remember returns a cached value when present and runs the supplied callback when it is missing. Cache::flexible supports a stale while revalidate pattern, allowing a slightly older value to be served while Laravel refreshes it after the response.
The hard part is not storing the value. It is deciding when the value stops being true. Name cache keys clearly, choose a time to live that matches the business consequence of stale information and remove or refresh the key when relevant data changes.
Never cache a permission or customer-specific result under a key shared by everybody. Performance improvements still have to respect tenancy, authorisation and privacy.
09
8. Move slow non-essential work onto queues
A user should not wait for work that does not affect the response they need now.
Email delivery, PDF generation, image processing, large imports, report building and external system synchronisation are common queue candidates. The web request can validate and save the important state, dispatch a job, then respond while a worker completes the slower task.
Queues change the shape of the responsibility rather than making it disappear. Jobs need sensible retries, timeouts, monitoring and idempotent behaviour so a retry does not send the same invoice twice. Workers need to be supervised and reloaded after deployment so they run the current code.
Keep synchronous work synchronous when the next screen depends on its result. Moving a payment decision or essential validation into the background can make the interface look faster while creating a confusing and unsafe workflow.
10
9. Reduce the work sent to the browser
Laravel may return HTML or JSON quickly while the page still feels slow because the browser receives large scripts, stylesheets and images.
Build front end assets for production. Remove code that is no longer used, split heavy functionality where it makes sense and avoid loading a large library across the whole application for one small component. Compress images, provide dimensions and responsive versions, and let browsers cache versioned assets for a long time.
A content delivery network can help geographically distributed users, but it is not the first answer to an oversized JavaScript bundle or an uncompressed photograph. Make the asset cheaper before paying to move it closer.
Measure what users experience as well as the server response. A quick API behind a blocked main thread is still a slow product.
11
10. Run an appropriate PHP version with OPcache enabled
PHP's OPcache stores precompiled script bytecode in shared memory. That avoids loading and parsing the same PHP files from scratch on every request. It should be part of a normal production PHP setup, with memory and revalidation settings chosen for the deployment model.
Keep PHP and Laravel on supported versions through planned upgrades. Newer does not mean automatically faster for every application, but supported releases provide current fixes, security maintenance and a healthier base for the rest of the work. Test the application, extensions and dependencies before changing the runtime.
Long-running Laravel services also need attention. Queue workers and Octane processes retain application state in memory, so the deployment process must reload them after new code is released. Laravel now provides a reload command for its long-running services.
Octane can improve throughput for suitable applications, but it is not a substitute for fixing poor queries, excessive payloads or slow external calls. Introduce a persistent application server only when measurement shows the normal request lifecycle is a meaningful part of the remaining problem and the team can operate it safely.
12
Improve one measured bottleneck at a time
The best performance work usually looks less dramatic than the before and after graph suggests. One relationship is eager loaded. One large query becomes a paginated list. One PDF moves onto a queue. Production caches become part of every deployment.
Each change removes unnecessary work while keeping the behaviour understandable.
Start with the slow user journey, record a baseline and identify where the time goes. Apply the smallest improvement that addresses that evidence, then run the same measurement again. Keep the changes that make a meaningful difference and resist cleverness that only improves a tiny isolated benchmark.
A fast Laravel website is not created by adding every performance feature. It is created by making the application do the right work, in the right place, at the right time.
If a Laravel application has become slow, difficult to release or risky to change, a focused review can separate database, code, queue and infrastructure problems before improvement work begins.
Useful questions
A measured Laravel performance review should answer:
- Which user journey is slow, and what is its current baseline?
- How much time is spent in PHP, the database, external services and the browser?
- Are configuration, events, routes and views cached during production deployment?
- Does production run with debug mode disabled and purposeful logging enabled?
- Are repeated relationship queries or unnecessarily large result sets present?
- Do frequent slow queries have suitable indexes and verified execution plans?
- Can stable calculations be cached without crossing customer or permission boundaries?
- Can slow non-essential work move to a monitored queue safely?
- Are scripts, styles and images making the browser slower than the server?
- Is PHP running with OPcache, supported versions and a reliable worker reload process?
- Did the same measurement improve after the change?


