In k6 v2, what does --compatibility-mode=extended add on top of base?
answer
- far weaker than the name suggests
- extended is the default
- one property, nothing else
- global aliased to globalThis
- no transpiling in either mode
basics
~20 sExactly one thing: extended defines global as an alias for globalThis, for the benefit of Node-oriented code. Base is plain Sobek. Extended is the default, and neither mode changes the ECMAScript level, TypeScript handling or module resolution.
solid answer
~40 sIn k6 v2 the flag is far weaker than its name suggests. `base` is plain **Sobek**, k6's Go JavaScript engine, with the k6 built-ins on top. `extended`, which is the default, is `base` plus a single property: `global` defined on the global object as an alias for `globalThis`, so Node-oriented library code that reaches for `global` does not fail on its first line. It selects no ECMAScript version, does not enable or disable TypeScript stripping, adds no Node APIs, and does not change module resolution. You set it with the `--compatibility-mode` flag or the `K6_COMPATIBILITY_MODE` environment variable, with the flag winning; you cannot set it from the script's exported `options` object.
code
bash · 3 linesk6 run script.js # extended, the default
k6 run --compatibility-mode=base script.js # global is undefined
K6_COMPATIBILITY_MODE=base k6 run script.js # same, via the environmentgo deeper
Know that extended is the default and that you almost never need to touch this flag. Running a normal k6 script, including a TypeScript one, requires no compatibility-mode setting at all.
Be able to state the delta precisely: extended adds global as an alias for globalThis and nothing else, and neither mode changes the ECMAScript level, TypeScript handling or module resolution.
Recognise the real use case. When a vendored dependency feature-detects on typeof global and picks a Node branch that then fails deep inside, switching to base is a targeted, explainable fix rather than a shot in the dark.
Treat it as a compatibility boundary to standardise. Decide once whether the team's bundled dependencies are built for a browser-like target, so nobody has to discover this flag by debugging a stack trace from inside a vendored library.
## What the flag is `--compatibility-mode` selects how k6 prepares JavaScript before its engine, **Sobek**, executes it. In k6 v2 the flag defaults to `extended`, and the alternative is `base`. Almost all the k6 material in circulation describes this flag as it behaved years ago, which is why it is such a reliable interview question: the honest answer today is "far less than you think". ## The one difference in k6 v2 `base` is plain Sobek — vanilla JavaScript as the ECMAScript standard defines it, with the k6 built-ins registered on top. `extended` is `base` **plus one property**: k6 defines `global` on the global object as an accessor that returns `globalThis`. | | `base` | `extended` (default) | |---|---|---| | engine | Sobek | Sobek | | `globalThis` | available | available | | `global` | **undefined** | alias for `globalThis` | | ES2015+ syntax | supported by Sobek | supported by Sobek | | `.ts` type stripping | on | on | | Node APIs (`fs`, `os`, `process`) | absent | absent | That is the whole delta. The alias exists purely so that library code written for Node, which reaches for the `global` object rather than `globalThis`, does not blow up on its first line. ## What the flag does not control - **It does not choose an ECMAScript version.** Sobek supports modern syntax natively in both modes; there is no down-levelling pass and no polyfill bundle in either. - **It does not turn TypeScript on or off.** k6 strips types from `.ts` files regardless of the mode. - **It does not add or remove Node APIs.** No mode gives you `fs`, `os`, `process` or `Buffer`. - **It does not change module resolution.** Bare specifiers such as `'lodash'` fail to resolve in both modes. - **It does not affect executors, thresholds, metrics or output** in any way. A useful way to hold all of this: in k6 v2 `--compatibility-mode` is a **runtime-shape** switch, not a **language-level** one. Nothing about the syntax k6 accepts, the module specifiers it can resolve, or the file types it can load changes when you flip it; exactly one property on the global object appears or disappears. In older k6 releases the flag did select a heavier transform pipeline, and the docs still carry a note saying the feature stopped having much impact from k6 v0.53 onward. The name outlived the behaviour. ## Where you can set it, and where you cannot There are exactly two places: 1. the CLI flag, `k6 run --compatibility-mode=base script.js`; 2. the environment variable, `K6_COMPATIBILITY_MODE=base k6 run script.js`. The CLI flag wins when both are present — k6 only consults the environment variable if the flag was not given explicitly. What you **cannot** do is set it from the exported `options` object in the script; the option reference lists the "Code / Config file" column for this setting as not applicable. This is a recurring shape in k6: being a knob does not make something a script-level option. An unrecognised value is rejected before the test starts, with an `invalid compatibility mode` error naming the accepted ones. ## The deprecated third value k6 historically offered a third mode for TypeScript and newer syntax. In k6 v2 the value is still parsed, but passing it logs a deprecation warning explaining that types are now stripped by default for `.ts` files and telling you to move to `base`, since the mode will be removed. Treat any tutorial that tells you to pass it in order to run TypeScript as out of date — running `k6 run script.ts` needs no flag at all. ## When `base` is actually the right choice Because the only thing `base` removes is the `global` alias, it is worth reaching for in one specific situation: **feature detection**. A bundled dependency that branches on `typeof global !== 'undefined'` will, under the default `extended` mode, conclude it is running in Node and take a code path full of Node APIs that do not exist — failing later and more confusingly than if it had simply taken its browser or standard branch. Switching that test to `--compatibility-mode=base` makes `global` undefined and steers such code down the branch that has a chance of working. Outside that case the default is fine, and choosing `base` for performance or strictness reasons buys nothing measurable — there is no transform pass being skipped, because in k6 v2 there is no transform pass to skip.
- Why would you deliberately choose --compatibility-mode=base for a k6 test?For feature detection. A bundled dependency that branches on `typeof global !== 'undefined'` concludes under `extended` that it is running in Node and takes a code path full of Node APIs k6 does not have. Under `base`, `global` is undefined, so the same code takes its browser or standards branch, which has a chance of working.
- Can a k6 script set its own compatibility mode in the exported options object?No. The setting is available only as the `--compatibility-mode` CLI flag or the `K6_COMPATIBILITY_MODE` environment variable; the option reference marks the code and config-file column as not applicable. The mode has to be decided before the script is parsed, so the script cannot choose it.
saying these in an interview costs you the question
- Says extended transpiles ES6+ down to ES5 with Babel
- Thinks base rejects modern JavaScript syntax
- Claims the mode controls whether TypeScript files run
- Believes extended unlocks Node core modules
- Sets compatibilityMode inside the script options object