“Why is this endpoint slow” is one of the most expensive questions in a Laravel team’s week, and most of the cost isn’t in the answer — it’s in how long it takes to even start looking. Someone adds Str::of(now()) timestamps around suspicious blocks of code. Someone else proposes New Relic, which means a procurement conversation, a data-processing agreement, and three weeks before the first flame graph appears. Meanwhile the endpoint is still slow, in production, for real users, today.
I got tired of that lag between “something is slow” and “I can see why” long before I ever thought about open-sourcing anything. So the base architecture already measures itself — every repository call, every cache read, every pipeline stage a service runs through is a potential timing point, because the classes were written knowing this question would come up eventually.
What the Pro tier adds is turning that self-awareness into something you actually look at without leaving your browser. MeasuresPerformance and MeasuresCachePerformance are opt-in traits — add them to a service or repository and every call it makes through the pipeline gets measured automatically. ServerTimingMiddleware assembles those measurements and writes them into the response as a Server-Timing header, which Chrome DevTools renders natively, in the Network tab, on every single request, with zero extra tooling installed. Open a request, open the Timing panel, and you see exactly how many milliseconds went to the repository, how many to the cache lookup, how many to the actual business logic — per request, in production if you want it there, without shipping a single log line to a third party.
class OrderService extends BaseService
{
use MeasuresPerformance;
public function place(array $data): PlaceOrderData
{
// measured automatically as "OrderService.place" — no manual instrumentation
return $this->throughPipes('place', $data, function ($payload) {
// ...
});
}
}
Server-Timing: app;desc="Bootstrap";dur=3.1,
db;desc="Database Queries (4)";dur=12.5,
OrderService.place;dur=72.4,
cache:orders.detail.42;desc="Cache hit: orders.detail.42";dur=0.3
Open DevTools → Network → click the request → Timing tab. That’s the whole setup.
The reason this belongs in the paid tier and not the free core isn’t that it’s more clever than the architecture. It’s that it’s a tool, not a convention. The response envelope and the exception hierarchy are decisions your whole team has to agree on once and never revisit — that’s what makes them foundation-shaped, and foundation-shaped things should be free and universal. Profiling is something you reach for when you have a specific, current problem to solve, the same way you’d reach for a paid APM subscription or a paid debugging tool. It’s utility, not convention, and utility is what funds the maintenance of the convention underneath it.
What surprised me building this wasn’t the middleware. It was how often the answer to “why is this slow” turned out to be a cache miss on a listing query I’d assumed was warm — visible instantly in the Timing panel, invisible in a generic request-duration log line that only tells you the total was slow, not which of the four things inside it actually cost the time.
If you’ve ever had “we should really add an APM tool” sit in a backlog for two quarters because of the procurement overhead, this is the version that installs with Composer and shows up in a browser tab you already have open.
Get it at https://packagist.org/packages/rupeshstha/core-foundation — part of the core-foundation Pro tier. Full setup, thresholds, and cache-hit timing: Server Timing