Laravel's Benchmark class can answer a narrow performance question in a few lines. The useful result comes from choosing the right question, controlling what is measured and knowing when a stopwatch is no longer enough.
01
Start with a decision, not a stopwatch
Performance work often begins with a confident sentence: this version must be faster. The confidence may come from fewer lines, a clever collection chain or a database query that looks more direct. None of those observations tells us how long the work takes in the application that will actually run it.
Laravel includes Illuminate\Support\Benchmark for this kind of small question. It measures how many milliseconds a callback takes, can repeat the callback and can compare several alternatives. That makes it useful while testing an implementation, investigating a slow method or checking whether an optimisation changed the part of the code it was meant to improve.
The important word is small. A benchmark can compare two ways of normalising customer reference strings. It can measure a query or a transformation. It cannot, on its own, explain why an entire page feels slow to a user.
Before running anything, write down the decision the number will inform. For example: should this import normalise 20,000 references with a collection pipeline or a simple loop? That is testable. Make the application faster is not.
02
Measure one callback with Benchmark::measure
Import the Illuminate\Support\Benchmark class, then pass a closure to Benchmark::measure. The method runs the closure and returns its duration as a floating point number in milliseconds.
A simple call can be described as: $duration = Benchmark::measure(fn () => normaliseReferences($references));. The result might be 3.842, meaning that particular run took roughly 3.842 milliseconds in that environment.
Laravel uses PHP's high resolution monotonic timer underneath. It records the time before the callback, runs the callback and converts the elapsed nanoseconds into milliseconds. The framework also asks PHP to collect garbage cycles before each measured run.
That implementation gives developers a convenient, consistent stopwatch. It does not remove the normal sources of variation in a computer. Other processes, thermal throttling, database state, file caches and the first use of a service can all move the result.
03
Repeat the work when one run is too noisy
Benchmark::measure accepts an iterations argument. Setting iterations to 100 runs the callback 100 times and returns the average duration. The same option is available to Benchmark::dd.
Repeated runs are useful when the code is short enough for normal machine activity to distort a single result. An operation reported as 0.08 milliseconds once and 0.12 milliseconds the next time may be functionally identical for the decision you are making. A larger sample helps reveal that the supposed difference is mostly noise.
More iterations are not automatically more truthful. A benchmark that queries the database 100 times may be testing a warmed connection and cache rather than the first request a customer experiences. Repeating code that changes state can also make every iteration different from the last.
Use enough iterations to see whether the result is stable, then run the complete benchmark again. If the ranking changes regularly, the evidence is not strong enough to justify a complicated optimisation.
04
Compare alternatives under the same conditions
Benchmark::measure can receive an array of named closures. Laravel measures each one and returns an array of durations using the same names. Benchmark::dd can display the same comparison immediately.
For the reference import, the array might contain Loop and Collection entries. Both callbacks should receive the same input and produce the same output. If one version trims values and the other quietly skips validation, the benchmark is comparing different work.
Keep shared setup outside the callbacks when it is not part of the question. Build the representative input once, then let each callback perform only the implementation being compared. If the question is the total cost of loading, parsing and normalising a file, include all three steps in both callbacks instead.
The boundary should match the decision. Excluding work simply because it makes a preferred option look quicker creates a precise answer to the wrong question.
| Method | What it accepts | What it returns | Best use |
|---|---|---|---|
| Benchmark::measure | One closure or an array of closures, plus optional iterations | Milliseconds as a float, or an array of durations | Record or compare timings in application code |
| Benchmark::value | One callable | A two item array containing the callback result and duration | Use the result while also seeing how long it took |
| Benchmark::dd | One closure or an array of closures, plus optional iterations | Formatted millisecond values, then execution stops | Quick investigation during local development |
05
Keep the result with Benchmark::value
Sometimes the callback produces a value you still need. Benchmark::value runs one callable once and returns a two item array containing the callback result and its duration in milliseconds.
A count example can be described as: [$count, $duration] = Benchmark::value(fn () => User::count());. The application can continue using $count while the developer records or inspects $duration.
Benchmark::value does not accept a set of alternatives or an iterations argument. It is designed for one operation where both output and timing matter. If the code has side effects, remember that the operation really happens. Measuring an email send, payment call or record update is not a harmless observation.
The returned value should also be checked. A fast implementation that returns the wrong rows has not won anything except a shorter route to a defect.
06
Use Benchmark::dd for a quick local answer
Benchmark::dd measures the supplied callback or callbacks, formats each average to three decimal places with ms appended, then passes the result to Laravel's dump and die helper.
It is useful in a temporary route, command or test while investigating an idea. You can name two scenarios, run each several times and see the result without creating reporting code.
The clue is in the final two letters. Execution stops. That makes the method unsuitable for normal application flow and something to remove before a change is completed. Use Benchmark::measure when the duration needs to be logged, asserted against a cautious threshold or passed elsewhere.
07
Use representative data and realistic conditions
A useful benchmark resembles the workload that matters. Ten tidy records tell you little about an import that regularly receives 50,000 rows with duplicated references, missing values and inconsistent spacing.
Build a repeatable dataset that includes normal volume and the awkward cases the operation must handle. Keep it fixed when comparing alternatives. If one callback receives a Laravel collection and the other pays the cost of creating it, record that difference deliberately rather than accidentally.
Environment matters too. A local laptop, a continuous integration runner and a production server have different processors, storage, extensions and background activity. Database and network latency can dominate a callback even when the PHP code inside it is trivial.
Treat local numbers as evidence about that local comparison. If the decision carries real commercial or operational weight, confirm it in a production-like environment and observe the complete user journey after release.
08
Know what the number leaves out
Laravel Benchmark reports elapsed time. It does not show memory growth, query count, query plans, external requests, queue delays, browser rendering, concurrency or the line of code responsible for the delay.
A callback can appear quick because a previous request filled the cache. Another can look slow because it opened the first database connection. An average can hide a handful of very slow runs that matter more to customers than the typical case.
Use query logging or database analysis for expensive queries. Use a profiler when you need to understand where execution time is spent. Use application performance monitoring and real user monitoring when the problem crosses requests, services and browsers. Use load testing when concurrency and capacity are the question.
Benchmark remains useful because it is small, built into Laravel and quick to remove. It should sharpen the next investigation, not replace every other performance tool.
09
Turn the result into a sensible engineering decision
The fastest implementation is not automatically the best one. A tiny timing improvement may not justify code that is harder to read, harder to test or more likely to be changed incorrectly later.
Look at the absolute difference as well as the ratio. An option that is twice as fast sounds dramatic, but moving from 0.02 to 0.01 milliseconds may have no visible effect on a request dominated by a 300 millisecond API call. Moving a repeated import step from two seconds to 200 milliseconds is a different decision.
Record the input size, environment, iteration count and code version with any result worth keeping. Otherwise the number will eventually be repeated without the conditions that gave it meaning.
Laravel's Benchmark class is most valuable when it replaces a hunch with a narrow piece of evidence. Measure the code that answers the question, repeat it carefully, check that both versions do equivalent work and stop when the difference is too small to matter.
If performance trouble runs through database queries, queues, integrations and front end behaviour, the next step is not a larger loop around Benchmark::measure. It is a proper application review that connects the technical evidence to the workflow users are waiting for.
Useful questions
Before trusting a Laravel benchmark, ask:
- What exact implementation decision will this timing inform?
- Do the compared callbacks perform equivalent work and return equivalent results?
- Is shared setup inside or outside the benchmark for a deliberate reason?
- Does the input represent realistic volume and awkward data?
- Will repeated iterations change database, cache or application state?
- Is the result stable across several complete benchmark runs?
- Does the absolute time saved matter to the user or operation?
- Would profiling, query analysis, monitoring or load testing answer the wider question better?
- Have the environment, input size, iterations and code version been recorded?


