skip to content

What does k6's summaryTimeUnit option change in the end-of-test summary?

level: juniorimportance: should knowfreq 40%

answer

  1. three letters, nothing else
  2. a display switch, not a measurement
  3. unset is not the same as ms
  4. the flag checks, the script does not
  5. counts and byte totals opt out

basics

~20 s

k6's summaryTimeUnit fixes the unit every duration is printed in throughout the end-of-test summary. It accepts only s, ms or us; left unset, k6 picks a readable unit per value instead, so columns may mix ns, us, ms and s.

solid answer

~40 s

`summaryTimeUnit` is a formatting option: it fixes the unit used for every time value in k6's end-of-test summary, including the `avg`, `med` and `p(N)` columns of `http_req_duration`. It accepts exactly three values — `s`, `ms` and `us`, the last of which prints with a `µs` suffix. Left unset, k6 chooses a unit per value, so one column can read `340.55µs` and another `1m30s`, which makes two runs awkward to diff. Note the asymmetry: `--summary-time-unit` rejects anything else outright, but a bad value in the script's `options` object is not validated and silently falls back to mixed units. It affects durations only — byte metrics still print as data sizes and a `count` column stays a plain integer.

code

javascript · 8 lines
javascript
export const options = {
  summaryTimeUnit: 'ms',
  summaryTrendStats: ['avg', 'min', 'med', 'max', 'p(90)', 'p(95)', 'p(99)', 'count'],
};

export default function () {
  // Every duration column above prints in ms; count stays a plain integer.
}

go deeper

for a junior

Remember the option exists, that it takes only s, ms or us, and that leaving it out makes k6 choose a unit for each value rather than defaulting to milliseconds.

for a middle

Explain that it is purely a rendering step over values stored in milliseconds, and that it applies to duration metrics only, leaving byte totals, rates and sample counts formatted by their own rules.

for a senior

Point out the validation asymmetry between the flag and the script options object, and why pinning a unit is what makes two summaries textually comparable across runs.

for a principal

Decide whether the unit belongs in each script or in the pipeline's environment, given that whatever downstream tooling parses summary text has to agree with that choice.

## What the option does `summaryTimeUnit` is an exported k6 option that fixes the unit used for **every time value in the end-of-test summary** — the `avg`, `min`, `med`, `max` and `p(N)` columns of `http_req_duration`, `iteration_duration`, `group_duration` and every other duration metric, plus the duration figures printed for non-`Trend` metrics. It is a formatting switch on the printed report; it changes no measurement and no stored value. ## The three accepted values | value | printed suffix | what k6 multiplies the internal value by | |---|---|---| | `s` | `s` | 0.001 | | `ms` | `ms` | 1 | | `us` | `µs` | 1000 | Two things fall out of that table: - k6 holds durations internally in **milliseconds**, which is why `ms` has a coefficient of 1. - The `us` setting prints the Greek micro sign, so the column reads `p(95)=205700µs`, not `205700us`. Every value is rendered to two decimal places under a fixed unit, so a fast and a slow metric are directly comparable down the report rather than each choosing its own scale. ## What happens when the option is not set Unset is the default, and it is not the same as `ms`. With no unit fixed, k6 picks a unit **per value**, choosing the one that keeps the number readable: - under a microsecond, nanoseconds — `812ns`; - under a millisecond, microseconds — `340.55µs`; - under a second, milliseconds — `204.57ms`; - a second or more, seconds, then minutes and hours as needed — `1m30s`. That is convenient to read and awkward to diff, because the unit attached to one column can change between two runs of the same script purely because the number crossed a boundary. Pinning the unit is what makes the text of two summaries line up. ## The validation asymmetry — measured, and easy to get wrong k6 does **not** apply the same strictness to all three surfaces. 1. The CLI flag `--summary-time-unit` is checked. Anything other than `s`, `ms` or `us` is rejected before the run with `invalid summary time unit 'sec', use 's', 'ms' or 'us'`. 2. The value written into the script's exported `options` object is **not** validated. Neither is `K6_SUMMARY_TIME_UNIT`. An unrecognised value from those two paths is not an error — the renderer simply does not find it in its unit table and falls back to the per-value mixed units described above. So `summaryTimeUnit: 'sec'` in a script does not fail the run; it quietly behaves as though you had never set the option. If a summary is not appearing in the unit you asked for, an unvalidated spelling in the script is the first thing to check. ## Which values it does and does not touch `summaryTimeUnit` applies only to metrics whose recorded values are durations. The rest of the summary is formatted by other rules entirely: - metrics carrying byte counts, such as `data_sent` and `data_received`, are rendered as human-readable data sizes regardless of this option; - `Rate` metrics, such as `checks` and `http_req_failed`, are rendered as a percentage; - anything else is printed as a plain number; - and the `count` column of a `Trend` — the number of values the sink recorded — is always a bare integer, because a sample count is not a duration in any unit. That last point catches people out: with `summaryTrendStats: ['avg', 'p(95)', 'count']` and `summaryTimeUnit: 's'`, the first two columns switch to seconds and the third stays an unconverted whole number. ## Which built-in metrics move when you set it Most of the metrics people read in a k6 summary are duration-valued, so pinning the unit changes almost the whole report: - the HTTP timing family — `http_req_duration` and the phase metrics `http_req_blocked`, `http_req_connecting`, `http_req_tls_handshaking`, `http_req_sending`, `http_req_waiting` and `http_req_receiving`; - the execution timings `iteration_duration` and `group_duration`; - protocol timings such as `grpc_req_duration` and the WebSocket connect and session durations; - any custom `Trend` you created with the time flag set, so it is treated as a duration. Counters like `http_reqs`, rates like `http_req_failed`, and the byte totals `data_sent` and `data_received` are all unaffected, because none of them holds a duration. ## Setting it, and where Like the column list, the unit is available on three surfaces: `summaryTimeUnit` in the exported options object, `K6_SUMMARY_TIME_UNIT` in the environment, and `--summary-time-unit` on the command line. Only the last of those is validated, which is the asymmetry above; the practical habit is to keep the value in the script where it is reviewed alongside the rest of the configuration, and to spell it carefully because nothing will tell you if you do not. ## How it relates to the column list The two summary options are orthogonal and are worth keeping straight. `summaryTrendStats` decides **which** statistics are printed for a `Trend`; `summaryTimeUnit` decides **what unit** the time-valued ones are printed in. Changing one never changes the other, and either can be set on its own. A common pairing is to pin both — a fixed column list and a fixed unit — so that the summary text of two runs of the same script differs only in the numbers, which is what makes it worth capturing as build output at all.

  • Why does k6 treat 'ms' as a coefficient of 1 for summaryTimeUnit?
    Because k6 stores duration samples internally in milliseconds. The renderer multiplies the stored value by 0.001 for `s`, by 1 for `ms` and by 1000 for `us`, so `ms` is the pass-through case and the other two are simple rescalings of the same underlying number.
  • What happens in k6 if summaryTimeUnit is set to 'sec' in the options object?
    Nothing visible fails. That path is not validated, the renderer does not find `sec` in its unit table, and it falls back to choosing a unit per value. The same value passed as `--summary-time-unit=sec` would instead abort with `invalid summary time unit 'sec', use 's', 'ms' or 'us'`.

saying these in an interview costs you the question

  • Claiming summaryTimeUnit accepts units like ns, m or h
  • Thinking unset means milliseconds
  • Believing it rescales the recorded metric values
  • Assuming an invalid value in options fails the run
  • Expecting it to convert the count column too