Back to blog

Laravel performance

Why Is My Laravel App Slow? How to Find the Real Performance Bottleneck

Learn how to diagnose a slow Laravel application by tracing the complete user journey across browser, network, PHP, database, queues and external services.

When a Laravel application feels slow, adding cache, queues or a larger server before locating the delay can waste effort and create new complexity. Trace one real user journey across the browser, network, PHP, database, external services and background work, then fix the part the evidence identifies.

01

A slow dashboard is not a diagnosis

Imagine a customer portal used by an operations team. Its dashboard loads accounts, active jobs, document totals and recent activity. It works quickly for a new customer with five jobs, but an established customer with several years of history waits long enough to wonder whether the click registered. Saving one record is normally fine, yet sometimes stalls while an external service responds.

That description contains several clues, but it does not identify the cause. The delay could be in the browser, network, Laravel request lifecycle, database, an external API or work that should have been handled by a queue. Adding Redis, a larger server or Laravel Octane before locating that delay can make the application more complicated without making the user journey meaningfully faster.

Turn the complaint into a repeatable journey. Record the page or action, the type of user, the account being viewed and what happened immediately before the delay. For the portal, the starting case might be an operations manager opening the dashboard for a customer with 1,200 jobs after signing in on a normal office connection.

Keep the expected result fixed while measuring. A change that makes the page fast by omitting recent activity or bypassing an authorisation check is not a performance improvement. It is a different, and probably unsafe, page.

02

Break the request into visible stages

A browser click passes through more than Laravel. The name must resolve, a secure connection must be made, the web server and PHP runtime handle the request, Laravel boots, middleware checks the user, application code gathers data, and the response travels back for the browser to render.

That sequence is why one timing number is not enough. A quick Laravel response can still produce a sluggish page when a large JavaScript bundle blocks the browser. A light front end cannot hide two seconds spent waiting for a payment, mapping or document service.

Where Laravel application time can disappear
LayerWhat to measureCommon clueUseful evidence
BrowserRendering, scripts, images and interaction delayThe server responds quickly but the screen appears lateBrowser network and performance tools
NetworkConnection time, latency and response transferRemote users are slower than office usersRequest waterfall and regional checks
Laravel and PHPRequest duration, memory and application workMost time remains after queries and external calls are removedApplication monitoring and profiling
DatabaseTotal query time, query count, returned rows and execution plansPages worsen as records growPulse, Telescope, query logs and database plans
External servicesConnection time, response time, retries and failuresThe same action varies despite unchanged local dataOutgoing request timings and provider status
QueuesWait time, run time, retries and failure rateThe page is quick but follow-up work arrives lateQueue monitoring and job records

The comparison below is not a shopping list of tools. It is a way to stop one layer being blamed for time spent somewhere else.

03

Measure the real environment, not only a fast laptop

Local development is excellent for understanding one request, but it is a poor substitute for production evidence. The database is usually smaller. Network calls may be mocked. The developer may have a warm cache, no real queue backlog and none of the traffic that competes for resources during a busy day.

Start with production-safe monitoring. Look for the routes that are slow most often, not only the single worst request. Compare typical performance with the slower end of the range because an average can hide a group of users having a consistently poor experience.

Laravel Pulse can show slow incoming requests, queued jobs, database queries and outgoing HTTP requests against configurable thresholds. That makes it useful for trends and recurring hotspots. It can answer whether the portal dashboard is broadly slow or whether the problem is concentrated around one customer, route or dependency.

Use logs and monitoring with care. A useful timing record needs a route, duration and enough business-safe context to group similar requests. It does not need passwords, full document contents or personal data copied into an analytics tool.

04

Use Telescope to understand one request in detail

Once monitoring identifies a route, Laravel Telescope can help inspect what happened inside a particular request. Its query watcher records SQL, bindings and execution time. Its request, job, cache, HTTP client and other watchers help connect work that would otherwise appear in separate logs.

Telescope is valuable during development and controlled diagnosis, but it is not something to expose casually. Request and query records can contain sensitive information, and recording everything on a busy production application creates its own storage and performance considerations. Authorise access, prune old records and enable the watchers needed for the investigation.

A Telescope record might reveal that the dashboard did not run one spectacularly slow query. It ran 180 individually quick queries because the page loaded the owner and document count separately for every job. The database looked healthy when each query was viewed alone, while the request as a whole was wasteful.

05

Measure cumulative database time, not only one slow query

Laravel can act when the total time spent querying the database during a request passes a threshold. This matters because many small queries can produce the same user-facing delay as one obvious slow query.

Capture query count, cumulative query time and the volume of data returned. Then inspect the code and database plan. An N+1 relationship may need deliberate eager loading. A list may need pagination. A query that filters and sorts a growing table may need a suitable index. A dashboard count may be loading full model collections when the database could return the count directly.

Do not eager load every relationship in response. That can replace query chatter with a large result, higher memory use and slower serialisation. Load what this page needs and verify that the response remains correct.

Database performance is also shaped by data distribution. A query that is quick for 99 small customers but slow for one large account still affects a real user journey. Test the shape of the business data, not only the total number of rows.

06

Check how the page behaves as data grows

Performance problems often hide until a customer succeeds. The portal is fast with ten jobs, acceptable with one hundred and uncomfortable with one thousand. That is not random. It is a growth curve.

Build a representative test dataset and repeat the same route at several sizes. Watch how request time, memory, query count, response size and browser render time change. If query count rises with every row displayed, investigate relationships and loops. If query count stays stable but the response grows dramatically, reduce selected fields, paginate the list or change the interface so it does not ask a person to process a thousand records at once.

A business decision may be more valuable than a code trick. A dashboard does not necessarily need every historical event. It might need current work, exceptions and a route to the archive. The faster design can be the clearer design when it follows the decision the user is trying to make.

07

Move background work without hiding important decisions

Some requests are slow because they do too much before answering the user. A form submission saves the record, creates a PDF, sends two emails, uploads a file and synchronises another system while the person watches a spinner.

Queues let Laravel handle suitable work after the important state has been committed. Document generation, notification delivery, image processing and non-critical synchronisation are common candidates. The interface can confirm that the request was accepted and show the follow-up status separately.

Queuing work does not remove it. Measure how long the job waits, how long it runs, whether it retries and what happens when it fails. Supervise workers and reload them during deployment so they run the current code.

Keep decisions synchronous when the next step depends on the answer. Payment authorisation, permission checks and validation that protects data integrity should not be pushed into the background merely to improve the response graph. A quick confirmation followed by a hidden failure is worse than an honest wait with a clear explanation.

08

Put boundaries around external services

An application can be healthy while a service it calls is slow. Address lookup, accounting, telephony, payment and document services add network and provider behaviour to the request.

Measure outgoing requests separately. Laravel Pulse can surface slow calls made through Laravel's HTTP client. Set deliberate connection and response timeouts, decide which failures can be retried, and prevent a retry from creating duplicate side effects. Where suitable, cache stable reference data or move non-essential synchronisation onto a queue.

The customer portal might call an external document service every time the dashboard opens simply to display a status. If that status can safely be updated in the background and stored locally, the dashboard no longer inherits the provider's response time. If the status must be live, the interface should handle a timeout without making the whole page appear broken.

Resilience and speed meet here. The fastest third-party call is still a risk if the entire operation stops when it fails.

09

Do not confuse server response time with page experience

Time to first byte describes only part of what the person experiences. After the response arrives, the browser may parse a large HTML document, download assets, run JavaScript, calculate layout and render complex components.

Use the browser's network and performance tools alongside server monitoring. Check bundle size, repeated requests, large images, unnecessary data in JSON responses and components that render far more rows than are visible. If the page becomes responsive long after Laravel finished, a database index will not solve the problem.

This is particularly relevant in Laravel applications using Inertia, Vue or another JavaScript front end. The back end and front end still form one customer journey. Measure them as one product rather than two teams defending separate dashboards.

10

Confirm the production baseline before adding architecture

Basic deployment settings should be correct before deeper changes are judged. Current Laravel guidance recommends running php artisan optimize during deployment so configuration, event mappings, routes and views are cached. Production debug mode should be off. Long-running queue, Reverb and Octane processes must be reloaded after new code is deployed.

The PHP runtime should use an appropriate supported version and OPcache should be configured for production. Workers should be supervised. The application health route and external monitoring should confirm that the service is reachable, although a healthy response alone does not prove important workflows are fast.

These are foundations, not a diagnosis. Route caching will not repair an N+1 query, and a larger server will not make a slow external service predictable. Fixing the baseline removes avoidable noise so the remaining evidence is easier to trust.

11

Reach for Octane or a larger server after the evidence

Laravel Octane can reduce framework boot overhead by keeping the application in memory between requests. More CPU or memory can also improve capacity when the current infrastructure is genuinely constrained. Both can be reasonable decisions.

They should come after the request has been measured. If database work or an external API dominates the timeline, keeping Laravel warm may make only a small visible difference. If inefficient work consumes every new resource provided, scaling the server can postpone the same problem at a higher monthly cost.

Octane also changes the application lifecycle. Long-lived processes require care around shared state and deployment. Use it because the remaining measured workload benefits from it and the team can operate it safely, not because “make Laravel faster” appeared on a task list.

12

Turn one investigation into a repeatable check

Performance work should leave behind more than a faster page. Keep a repeatable route, representative account and baseline measurement. Add monitoring for the condition that mattered, whether that is cumulative query time, slow outgoing requests, queue wait or browser payload size.

After each change, run the same journey again. Compare the complete user experience, check correctness and watch production behaviour over time. Remove instrumentation that was only safe for a short investigation, but keep enough evidence to detect the problem returning.

For the portal dashboard, the outcome might be a bounded list of current jobs, deliberate eager loading, locally stored document status and a background synchronisation job with visible failure handling. Those are possible remedies only after the request timeline shows they address the real delay.

13

Make the slow request explain itself

Laravel applications are rarely slow because Laravel needs a magical speed package. They become slow when useful features accumulate without enough visibility into how the work is performed.

Start with one user journey. Reproduce it with realistic data. Separate browser, network, application, database, external service and queue time. Fix the largest measured source of delay, then repeat the test.

That approach is less exciting than installing five optimisation packages before lunch. It is also far more likely to make the application faster without making it harder to understand.

If a Laravel application has become slow, inconsistent or difficult to diagnose, I can review the request path, data access, queues, integrations and deployment setup, then turn the evidence into a practical order of improvements.

Useful questions

Before changing a slow Laravel application, check:

  • Can the slow user journey be repeated with the same account and data?
  • Is the delay in the browser, network, Laravel, database or an external service?
  • Are production timings available without recording sensitive data?
  • Have query count and cumulative database time both been measured?
  • Does the route behave differently as customer data grows?
  • Is non-essential work holding the web request open?
  • Are queue wait time, run time, retries and failures visible?
  • Do external calls have sensible timeouts and failure handling?
  • Is the Laravel and PHP production baseline configured correctly?
  • Has the same complete journey been measured after the change?
Explore Laravel and Vue development
Daniel Mills

Written by Daniel Mills

Business understanding and hands-on software delivery.

I help owners and teams improve the software they rely on, replace fragile processes and turn new ideas into practical systems people can actually use.