The Performance dashboard

The Performance tab in System Health: fuel gauges, the groups table, read amplification, and drilling down to single events.

#The Performance dashboard

The Performance tab in System Health answers three questions in order: Am I OK? What is consuming my quota? Why is it expensive? Each level of the tab links one level deeper, down to a single recorded request.

A time-range selector (1h / 6h / 24h / 7d / 30d / 90d) and a Metrics/Runs switch stay at the top of every view. Every drill-down state is reflected in the URL, so you can link a colleague straight to the event you're looking at.

#Fuel gauges — am I OK?

The landing view shows one gauge per free-tier limit: worker requests per day, D1 rows read per day, D1 rows written per day, KV reads per day, and Analytics Engine writes per day. Each gauge is a progress bar against the free-tier limit, plus a projection: at the current rate, how long until you hit it. "30+ days of headroom" means you can relax; "~2 days" means read on.

Gauges always show a rate, never a raw total. Whatever range you pick, the traffic in it is scaled to the limit's own period before the comparison — an hour of traffic is projected to a full day, and a week of traffic is averaged down to one. That is why widening the range changes your confidence in a number without inflating the number itself.

Below the gauges, the top hints each link to the view or doc page that helps you act on them.

Note

The Performance tab reads Workers Analytics Engine, which EmuView writes one datapoint to per request. It needs both the ANALYTICS binding and Cloudflare API credentials; without either, the tab shows a setup card naming the missing piece rather than a gauge. Local dev has no queryable WAE.

#Groups table — what is consuming it?

Open the groups view to see consumption broken down. Group by endpoint, collection, or status, and sort by any column:

Column What it tells you
Requests Traffic volume for the group
Rows read Total D1 rows scanned — the number that drains the biggest gauge
Rows/request Average cost per call
Read amplification Rows read ÷ rows returned (see below)
D1 queries/request Average query count — high values suggest per-record querying
p50 / p95 latency Typical and worst-case response times
Errors Error count in the range

Rows with outlier values carry severity chips so the expensive group is visible without sorting.

#Read amplification

Read amplification is rows read divided by rows returned. A perfectly indexed list query has amplification near 1×: the database scans roughly the rows it returns. When a filter or sort has no index, D1 scans the whole table to find the matching page — a query returning 25 rows from a 10,000-row table shows 400× amplification.

As a rule of thumb, amplification above 25× on a collection's list or filter traffic means an index on the filtered field would pay for itself. Index tuning walks through the fix.

#Endpoint detail — why is it expensive?

Click a group row to see its detail: a timeseries of rows read, latency, and request count for the selected range; a per-metric breakdown card (average D1 queries, KV operations, DO calls, subrequests per request); and any hints scoped to this group.

Below that, a "most expensive recent events" table lists individual recorded requests from the range, sorted by rows read. This is where an abstract average becomes a concrete request you can inspect.

#Event drawer — what exactly happened?

Click an event to open a drawer with the full record: timestamp, method, path, status, project, collection, and the complete resource receipt — D1 queries, rows read and written, KV operations, DO calls, subrequests, and duration.

One honest limitation: historical events don't include SQL text. EmuView records the numbers for every request but never persists query text or parameters. The drawer's reproduce button bridges the gap — it copies a curl command for the same path with X-Cost-Debug: 1 set, so you can re-run the call live and get a full cost receipt including the slowest query's SQL.

#Runs — published profile reports

The Runs view lists cost-profile reports published with npm run cost:profile -- --publish: one entry per run with its date, git commit, and verdict. Click a run to see its per-scenario table, or select two runs for a side-by-side diff. This gives the release ritual a durable, shareable home — a bug report can link to the exact run where a number regressed.