In a Karate feature suite, what must the `karate-config.js` file contain, and what does Karate do with the value it produces?
answer
- One file, evaluated before scenarios
- It is JavaScript, not a properties file
- Its return value is a map
- Map keys become scenario variables
- Per scenario, not per suite
basics
~20 skarate-config.js holds a JavaScript function that returns a map. Karate evaluates it before every top-level scenario and applies each key of that map as a scenario variable, so no step-definition or glue class is involved.
solid answer
~40 s`karate-config.js` is a JavaScript source whose content evaluates to a **function returning a map** — conventionally `function fn() { return { baseUrl: 'http://localhost:8080' } }`. Karate calls that function before every top-level `Scenario`, and before every `Examples` row of a `Scenario Outline`, then applies each top-level key of the returned map as a scenario variable: `baseUrl` in the map is simply `baseUrl` in a step. The `karate` object is already in scope inside the file, so the function can read `karate.env` or `karate.properties['some.prop']` and branch on them. The file is optional — when Karate cannot find it the run continues with no config variables set, and you only learn about it when a step references a name that was never defined.
code
javascript · 9 linesfunction fn() {
var config = {
baseUrl: 'http://localhost:8080',
adminUser: 'admin',
// a function in the map becomes a helper every scenario can call
idFor: function (name) { return name.toLowerCase() + '-1'; }
};
return config;
}go deeper
Recall the shape: a JavaScript function that returns a map, and every key in that map is a variable your steps can use straight away.
Explain the timing. It is evaluated before every top-level scenario and every Examples row, and the keys are applied as ordinary variables that a scenario can shadow with its own def.
Know what per-scenario evaluation costs. Work written inline in the config function repeats for every scenario on every thread, and a missing file degrades silently into undefined-variable failures deep in a run.
Weigh what belongs in an always-loaded file at all. Every key is re-created per scenario across the whole suite, so a bloated config trades run-time cost and coupling for convenience nobody measured.
## What the file must contain `karate-config.js` is not a properties file and not a Karate-specific format. It is plain JavaScript, and Karate evaluates the whole source expecting it to yield a **function**. The conventional shape is a single named function that builds an object and returns it: ```javascript function fn() { var config = { baseUrl: 'http://localhost:8080', adminUser: 'admin', timeoutMs: 5000 }; return config; } ``` What matters is not the function's name but that the source produces something callable returning a map. ## What Karate does with the returned map Every **top-level key** of that map is applied as a scenario variable of the same name. There is no import, no registration and no accessor: a key called `baseUrl` is readable in the very next step as `baseUrl`. ```gherkin Scenario: uses a config variable directly Given url baseUrl And path 'cats' When method get Then status 200 ``` That is the mechanical difference from a step-definition framework. There is no glue package to point at, no hook class to register, and no context object to inject — the config file simply seeds the variable space that every step already reads from. Values are ordinary Karate variables once applied, so a scenario can shadow one with its own `def` without touching the file, and a JavaScript **function** returned in the map becomes a callable helper available to every scenario. ## How often it runs This is the part that surprises people: the function is evaluated **before every top-level scenario**, not once per suite, and a `Scenario Outline` counts each `Examples` row as its own scenario. A hundred scenarios means a hundred evaluations. | Aspect | `karate-config.js` | |---|---| | Format | JavaScript source evaluating to a function | | Return value | a map (JSON-like object) | | Effect of each key | becomes a scenario variable of that name | | Evaluated | before every top-level scenario, and every `Examples` row | | Not evaluated for | a feature reached through `call` / `callonce` | | Missing file | not an error — no config variables are set | Two consequences follow directly: 1. **Anything expensive in the file is paid per scenario.** A blocking HTTP sign-in written straight into the function multiplies across the suite, and across every thread in a parallel run. 2. **Nothing mutated by one scenario survives into the next.** Each scenario gets a freshly evaluated map, so a scenario that mutates a config-supplied object cannot leak that mutation into its neighbours — which is exactly what makes scenarios independently runnable. ## What is in scope inside the file The `karate` object is bound before the config function runs, so the function can branch on run-time inputs: - `karate.env` — the current environment name, or `null` when nothing set it. - `karate.properties['some.prop']` — reads a JVM system property, the usual way a build passes a port or a URL in. - `karate.log(...)` — useful for proving which config actually loaded. ## Common traps - **Treating it as suite-level setup.** It is per-scenario. If you need something done once, the config file is the wrong place to do the work directly. - **Expecting a missing file to fail loudly.** It does not. The run proceeds and fails later, in a step, on a name that was never defined — a much worse error message than a missing-file error would have been. - **Returning nothing.** A function that computes variables but forgets `return config` contributes no variables at all, silently. - **Assuming a called feature re-runs it.** It does not; a feature reached through `call` inherits the caller's variables instead. - **Putting large helper libraries in it.** Everything in the returned map is re-created per scenario. ## It is the same mechanism as a shared-scope call The config file is not a special case bolted onto the engine. Karate already has one rule that says *a map-like value applied without an assignment contributes each of its key-value pairs as a variable* — the same rule behind `call read('helpers.feature')` written with no `def` in front of it. `karate-config.js` is that rule, applied automatically at scenario start. Knowing that removes most of the mystery: there is nothing a config file can produce that a step could not have produced, a config key is not privileged and can be shadowed like any other name, and everything true of a returned map elsewhere in Karate — including that a JavaScript function in the map becomes a callable name — is true here too. ## Keep it to what nearly everything needs Because it is evaluated per scenario, `karate-config.js` is the wrong place for anything that is only needed by a few features. Moving a routine into it makes the routine global, and global has a price paid on every scenario in the suite: the object is rebuilt, the function is re-created, and any work in the function body runs again. The guidance that ships with Karate is explicit about this — move something into the config file only when nearly *all* your feature files need it, because a bloated configuration costs both run time and readability. A useful test before adding a key: would you be comfortable with this value being re-computed once per scenario, on every thread, for the whole suite? If not, it does not belong in the raw body of the config function.
- What happens in a Karate run when `karate-config.js` cannot be found at all?Nothing fails at that point. Karate records that no config was found, sets no config variables, and carries on. The failure surfaces later as a step referencing an undefined name, which is why a suite that mysteriously loses every variable is usually a config-location problem rather than a config-content problem.
- If `karate-config.js` runs before every scenario, is it a good place to fetch an auth token?Not directly. Written inline, the fetch is repeated for every scenario and every `Examples` row, on every thread. The file is the right *place* to expose the token as a variable, but the work behind it should go through one of Karate's caching call forms so the network round trip happens once rather than once per scenario.
- Can a scenario override a value that came from `karate-config.js`?Yes. Config keys are applied as ordinary scenario variables, so a plain `* def baseUrl = 'http://other'` in the scenario or its `Background` shadows the config value for that scenario only. The next scenario starts from a freshly evaluated config again.
Think of it as the opening line of every scenario that you never have to type: Karate re-reads it before each one and drops the same set of names into scope.
saying these in an interview costs you the question
- Says karate-config.js is read once per suite run
- Thinks it must be a properties or JSON file, not JavaScript
- Expects a missing karate-config.js to fail the run immediately
- Believes step definitions are needed to expose its values
- Thinks each scenario must def the config keys before use
- Assumes an Examples row reuses the previous row's config