skip to content

Which statistics can k6's summaryTrendStats option list, and what does it print by default?

level: middleimportance: must knowfreq 58%

answer

  1. one list, every Trend metric
  2. five words plus a percentile form
  3. parentheses are not optional
  4. six tokens by default
  5. assignment replaces, never appends

basics

~10 s

k6's summaryTrendStats accepts avg, min, med, max, count and p(N) for N between 0 and 100. It defaults to avg, min, med, max, p(90), p(95), and any list you set replaces that default entirely.

solid answer

~40 s

`summaryTrendStats` chooses which columns the end-of-test summary prints for every `Trend` metric, and in which order. The accepted tokens are `avg`, `min`, `med`, `max`, `count`, and any percentile written `p(N)` with `N` a number from 0 to 100, fractions included, so `p(99.9)` is valid. Matching is exact and case-sensitive, and the parentheses are mandatory: `p95` is rejected with `invalid trend stat 'p95', unknown format`. With the option unset, k6 uses `["avg", "min", "med", "max", "p(90)", "p(95)"]`. The list you supply replaces that default rather than extending it, so adding `p(99)` means writing all seven tokens. The same list is settable via `K6_SUMMARY_TREND_STATS` or `--summary-trend-stats`.

code

javascript · 9 lines
javascript
export const options = {
  // The default six, plus p(99). The array replaces the default,
  // so every column you still want has to be listed again.
  summaryTrendStats: ['avg', 'min', 'med', 'max', 'p(90)', 'p(95)', 'p(99)'],
};

export default function () {
  // ... requests here feed http_req_duration, a Trend metric
}

go deeper

for a junior

Recall the six default tokens and that percentiles are written p(90), with parentheses. Knowing where the option goes in the exported options object is enough at this stage.

for a middle

Explain that the array replaces the default rather than extending it, that avg, min, med, max, count and p(N) are the whole accepted vocabulary, and that N may be fractional between 0 and 100.

for a senior

Show you know the list is validated before the run starts and that a bad token stops k6 outright, and that the option is one test-wide setting rather than something you can vary per metric.

for a principal

Weigh the cost of a wide default column set across every team script against the readability of the report, and decide whether the list belongs in each script or in the environment for the whole pipeline.

## What `summaryTrendStats` controls k6 records a `Trend` metric — the built-ins `http_req_duration`, `iteration_duration`, `group_duration` and friends, plus any `Trend` you construct from `k6/metrics` — into a sink that keeps every value the run observed. The end-of-test summary prints one line per metric, and for a `Trend` that line is a run of `label=value` pairs such as `avg=204.57ms min=203.31ms med=204.57ms max=205.82ms p(90)=205.57ms p(95)=205.7ms`. `summaryTrendStats` is the exported option that decides **which labels appear and in what order**. It is one test-wide list of strings: every `Trend` metric in the report gets the same columns, and there is no per-metric form of the option. ## The tokens k6 accepts | token | what k6 prints for the metric | |---|---| | `avg` | the arithmetic mean of every value the sink recorded | | `min` | the smallest recorded value | | `med` | the median, computed internally as `p(50)` | | `max` | the largest recorded value | | `count` | how many values the sink recorded | | `p(N)` | the Nth percentile, where `N` is a number from 0 to 100 | The parsing rules behind that table are strict: - The five word tokens are matched **exactly and case-sensitively**. `AVG`, `mean`, `median` and `p50` are not tokens. - `p(N)` needs its parentheses. `p95` is rejected; `p(95)` is accepted. - `N` may be fractional — `p(99.9)` and `p(99.99)` are both fine — and must satisfy `0 <= N <= 100`, so `p(101)` and `p(-1)` are rejected. `p(0)` resolves to the minimum and `p(100)` to the maximum. - `med` and `p(50)` produce the same number; list both and you get two identical columns. - `count` is the one token that is never rendered as a duration. It always prints as a plain integer, even for a time-valued metric and even when `summaryTimeUnit` is set. ## The default list, and why adding a column means restating it When the option is not set at all, k6 uses `["avg", "min", "med", "max", "p(90)", "p(95)"]`. The important mechanical detail is that the option **replaces** that list rather than extending it: k6 only substitutes the default when the option is absent, so any array you supply becomes the complete column set. Adding one column is therefore a rewrite: 1. Start from the six default tokens. 2. Append the one you want — `p(99)`. 3. Assign the whole seven-element array back to `summaryTrendStats`. Writing `summaryTrendStats: ['p(99)']` in the belief that it appends is the classic mistake; it silently leaves you with a single-column report. ## How the columns are rendered The order of the list is the order of the columns. k6 walks your tokens in sequence, renders each value, and joins the results as `token=value` pairs separated by spaces, using the token string itself as the printed label — so a list ending in `p(99)` produces a trailing `p(99)=812.4ms` on every `Trend` row. k6 also measures the widest rendered value per column position across all metrics and pads to it, which is what keeps the columns aligned down the report. Two consequences follow: reordering the list visibly reorders the report, and one metric with an unusually wide value widens that column for every metric. ## Where the list can be set k6 exposes the same list on three surfaces, all carrying the same tokens: - the exported options object in the script — `summaryTrendStats: ['avg', 'p(95)', 'p(99)']`; - the environment variable `K6_SUMMARY_TREND_STATS`, as a comma-separated string; - the CLI flag `--summary-trend-stats="avg,p(95),p(99)"`. The script form is the one to reach for when the columns are part of what the test *is* and should travel with it in version control. The flag is the one to reach for when you want a wider set for a single investigation without editing a shared script. Whichever surface supplies the value, it is a whole-list replacement — there is no syntax anywhere for adding a single token to whatever was configured elsewhere. ## What an invalid token does Whichever surface supplied it, k6 validates the whole list before the test starts and refuses to run on a bad token. A token that does not match a word token and is not shaped like `p(...)` produces `invalid trend stat 'p95', unknown format`; a correctly shaped percentile with an out-of-range or unparseable number produces `invalid percentile trend stat value 'p(101)', provide a number between 0 and 100`. Nothing is silently dropped, and no partial column set is printed. ## What the option does not reach `summaryTrendStats` is a **reporting** setting and nothing else. It selects columns in the metrics table; it does not create, remove or influence any threshold, and it does not affect the process exit code. The token set here is also not the same set a `Trend` threshold expression will accept — `count` is a legal summary column, for instance — so treat the two lists as separate vocabularies rather than assuming what works in one works in the other.

  • What does k6 do if summaryTrendStats contains a token it cannot parse?
    It validates the whole list before the run starts and refuses to start. A malformed token gives `invalid trend stat 'p95', unknown format`; a percentile outside 0-100 gives `invalid percentile trend stat value 'p(101)', provide a number between 0 and 100`. k6 never drops the bad token and runs with the rest.
  • Can different Trend metrics get different columns in one k6 summary?
    No. `summaryTrendStats` is a single test-wide list, and every `Trend` metric in the report is rendered with the same columns in the same order. If a threshold names a percentile that is not in the list, k6 does add that value to the metric's entry in the thresholds section, but the metrics table itself stays uniform.
  • Is `med` in k6's summaryTrendStats different from `p(50)`?
    No. k6 resolves `med` by calling the Trend sink's percentile function with 0.5, which is exactly what `p(50)` does. Listing both simply prints two columns holding the same number, under two different labels.

saying these in an interview costs you the question

  • Believing summaryTrendStats appends to the default list
  • Writing p95 or p 95 instead of p(95)
  • Assuming only whole-number percentiles are accepted
  • Thinking mean or median are valid tokens
  • Expecting a bad token to be ignored rather than fatal
  • Thinking the option can be set per metric