Which tags does k6 attach to metric samples by default, and what does options.systemTags change?
answer
- two sets, default and opt-in
- your list replaces, never extends
- fourteen by default, four optional
- two of them are not indexed
- a misspelling is dropped in silence
basics
~10 sk6 v2 emits fourteen system tags by default: proto, subproto, status, method, url, name, group, check, error, error_code, tls_version, scenario, service and expected_response. The systemTags option replaces that set rather than extending it.
solid answer
~40 sk6 v2 defines eighteen system tags. Fourteen are on by default — `proto`, `subproto`, `status`, `method`, `url`, `name`, `group`, `check`, `error`, `error_code`, `tls_version`, `scenario`, `service` and `expected_response` — and four are opt-in: `vu`, `iter`, `ip` and `ocsp_status`. You change the set with the `systemTags` option, or the equivalent `--system-tags` flag or `K6_SYSTEM_TAGS` variable. The detail that catches people out is that your list **replaces** the default set rather than adding to it, so `systemTags: ['status', 'method']` leaves you with exactly those two and nothing else. An unrecognised name in the list is discarded silently, so a typo removes a dimension with no error. And `vu` and `iter` are non-indexable: k6 stores them as sample metadata, so a selector such as `http_req_duration{vu:3}` warns and matches nothing.
code
javascript · 12 linesimport http from 'k6/http';
export const options = {
// Replaces the default set - only these four system tags are emitted
systemTags: ['status', 'method', 'name', 'group'],
vus: 1,
iterations: 1,
};
export default function () {
http.get('https://quickpizza.grafana.com/');
}go deeper
Know that k6 tags samples for you with things like status, method, url, name, group and scenario, and that you did not have to write anything for those to appear.
Be able to say which tags are on by default versus opt-in, and state clearly that systemTags replaces the default set. That replacement is the point of the question.
Bring the two operational edges: unknown names are dropped silently, and vu and iter land as metadata, so selectors built on them warn and match nothing.
Frame trimming systemTags as the one lever that removes dimensions rather than adding them, and as irreversible for that run's results once it has finished.
## What a system tag is A **system tag** is a key/value pair k6 attaches to metric samples by itself, without you writing anything. They are the dimensions every k6 result already has: which status came back, which method was used, which scenario emitted the sample. In k6 v2 the set is fixed — you cannot invent a new system tag, you can only choose which of the existing ones are emitted. k6 v2 defines eighteen system tags in total, split into two groups by whether they are on by default. ## The two groups | Group | Tags | Notes | | --- | --- | --- | | **On by default (14)** | `proto`, `subproto`, `status`, `method`, `url`, `name`, `group`, `check`, `error`, `error_code`, `tls_version`, `scenario`, `service`, `expected_response` | The dimensions every run gets for free | | **Opt-in (4)** | `vu`, `iter`, `ip`, `ocsp_status` | Emitted only if you name them | A few of the defaults are worth pinning down, because their names invite guesses: - `name` is the **request name**, which defaults to the cleaned request URL — it is not the metric's name and not the scenario's name. - `error` holds a non-HTTP error message such as a DNS or connection failure, while `error_code` holds k6's numeric error code; a 4xx or 5xx response sets `error_code` but not `error`. - `expected_response` is `true` or `false` according to the response callback, which by default treats 2xx and 3xx as expected. - `service` and `method` do double duty for gRPC — `method` carries the RPC method name there. - `group` carries the full `::`-joined group path, and `scenario` the name of the scenario the sample came from. ## Changing the set The set is controlled by the `systemTags` option, reachable the usual three ways: the `systemTags` key in the exported `options` object, the `--system-tags` CLI flag, or the `K6_SYSTEM_TAGS` environment variable. All three take a list of tag names. The behaviour that catches people out is that **the list replaces the default set; it does not add to it**. Writing `systemTags: ['status', 'method']` does not mean "the defaults plus these two" — it means "these two, and nothing else", so `group`, `name`, `scenario` and the rest stop being emitted. If you want the opt-in `vu` tag, you have to list every default you still want alongside it. When the option is not set at all, k6 falls back to the 14-tag default set. There is a second sharp edge: an unrecognised name in the list is **silently discarded**, not rejected. A typo such as `'sceanrio'` costs you the `scenario` tag with no error and no warning, and the run proceeds. Read the emitted tags in your output, not the option, to confirm what you actually got. ## Indexed tags versus metadata Two of the system tags — `vu` and `iter` — are **non-indexable**. When k6 records one, it goes into the sample's *metadata* rather than into its tag set. Metadata travels with the sample but does not form part of the sample's time series identity, and that has one very visible consequence: a sub-metric selector of the form `metric{key:value}` matches on tags, so a selector such as `http_req_duration{vu:3}` can never match anything. k6 recognises the mistake and logs a warning saying the high-cardinality `vu` tag was made non-indexable and selectors based on it will not work correctly, with the same warning for `iter`. This is also why k6 keeps an eye on how many distinct tag combinations a run produces. Every unique combination of tag values on a metric is a separate time series held in memory, and once a run passes 100,000 of them k6 logs a warning naming the count and the suggested limit, and pointing at the `name` tag and URL grouping as the fix. The limit then doubles, so the warning repeats rather than spamming. ## Practical guidance 1. Leave the defaults alone unless you have a concrete reason. They are cheap because their values are drawn from small sets — a handful of methods, a handful of statuses. 2. Turn `vu` or `iter` on only for debugging a specific run, and remember they arrive as metadata. 3. If you trim `systemTags`, write out the full list you want, then check the output shows exactly those tags — the silent discard of unknown names means the option is not self-validating. 4. Reach for `ip` and `ocsp_status` when you are actually chasing a resolution or certificate problem; both add a dimension whose value varies per host.
- How do you enable k6's vu system tag without losing the defaults?List every default you still want alongside it, because `systemTags` replaces rather than extends. Also remember `vu` arrives as sample metadata rather than an indexed tag, so it will still not work inside a `metric{key:value}` selector.
- What does k6 do with an unrecognised name in the systemTags list?It discards it silently — no error, no warning, and the run proceeds without that dimension. Verify against the tags actually emitted rather than against the option you wrote.
- Why does k6 treat vu and iter differently from the other system tags?Their values are effectively unbounded, so indexing them would multiply a run's time-series count by the VU count and iteration count. k6 records them as metadata, which travels with the sample but is not part of its series identity.
saying these in an interview costs you the question
- Thinks systemTags adds to the default set rather than replacing it
- Says vu and iter are indexed tags usable in a selector
- Claims you can define a brand-new system tag name
- Expects k6 to error on a misspelled system tag name
- Confuses the name tag with the metric's own name