In a Karate feature file, what does an `@env=dev` tag on a scenario do, and what happens to that scenario when `karate.env` is not set at all?
answer
- A tag, but not a tag expression
- It gates on the environment name
- A list accepts any of the names
- The two forms differ when unset
- Ignored inside a called feature
basics
~20 s@env=dev runs that scenario only when karate.env is dev; a comma-separated list accepts any of the names. If karate.env is not set, the scenario is skipped. Its mirror, @envnot=dev, skips when karate.env is dev and runs when it is unset.
solid answer
~40 s`@env=dev` restricts a scenario to runs where `karate.env` holds `dev`; `@env=dev,qa` accepts either. `@envnot=prod` is the mirror — it skips the scenario when `karate.env` is `prod` and lets it run otherwise. The asymmetry to remember is what happens with **no environment set**: `@env=dev` **skips** (the value is `null` and matches nothing), while `@envnot=prod` **runs**. Both are checked as their own selection step, ahead of whatever tag expression the run was given, so they are not part of the and/or/not tag grammar and cannot be composed with it. And like `@ignore`, they are **top-level selection filters only** — a feature reached through `call` runs all its scenarios regardless of environment tags. That makes them a way to shape which scenarios a given environment's run contains, not a safety interlock inside a called flow.
code
gherkin · 15 lines@envnot=prod
Feature: fixture management
@env=dev,local
Scenario: reset the fixture data
Given url baseUrl
And path 'admin', 'reset'
When method post
Then status 204
Scenario: read the catalogue
Given url baseUrl
And path 'catalogue'
When method get
Then status 200go deeper
Recall the two spellings and their direction: @env=dev restricts a scenario to that environment, @envnot=prod excludes it from one, and both accept a comma-separated list.
Explain the unset case and its asymmetry — @env= skips when nothing is set while @envnot= runs — and that the check happens before any tag expression the run was given.
Know the limit. These are top-level selection filters, so a called feature ignores them, and a misspelled environment silently shrinks a run rather than failing it.
Decide where environment safety actually lives. A tag shapes a selection; only a check on the resolved target inside the scenario stops the wrong host being written to.
## What the tags select Karate recognises two environment tags on a `Feature` or a `Scenario`: - **`@env=dev`** — run this scenario only when `karate.env` is `dev`. A comma-separated list, `@env=dev,qa`, accepts any of the listed names. - **`@envnot=prod`** — the mirror. Skip this scenario when `karate.env` is `prod`, run it otherwise. It too takes a list. They exist because the environment steering the config chain and the set of scenarios worth running against that environment are usually related. A scenario that seeds test data has no business against a shared staging host; a scenario that exercises a feature flag only enabled in one environment cannot pass anywhere else. ```gherkin @env=dev,local Scenario: reset the fixture data Given url baseUrl And path 'admin', 'reset' When method post Then status 204 ``` ## The unset case, and its asymmetry This is the part that trips people up, and the two tags behave **oppositely**: | `karate.env` | `@env=dev` | `@envnot=dev` | |---|---|---| | `dev` | runs | skipped | | `qa` | skipped | runs | | not set (`null`) | **skipped** | **runs** | Read the bottom row carefully. With nothing set, `@env=dev` matches nothing and the scenario is skipped — a local run with no `-Dkarate.env` quietly loses every environment-tagged scenario. `@envnot=dev`, on the other hand, runs, because `null` is not `dev`. The practical reading: **`@env=` is opt-in and `@envnot=` is opt-out**, and the unset case falls on the safe side of each. Neither is a substitute for a real guard. If a scenario must never touch a particular host, the check belongs in the scenario, not only in a tag. ## Where in selection they are evaluated Both tags are evaluated as their own step during scenario selection, **before** whatever tag expression the run was given. Two things follow: - They are **not** part of the tag-expression grammar. You do not compose `@env=dev` into an and/or/not expression; it is a separate mechanism that happens to be spelled as a tag. - A run's tag expression cannot re-enable a scenario the environment check already excluded. The environment gate comes first. ## They are top-level selection only Environment tags share a rule with `@ignore`: they filter which scenarios a **top-level** run selects. A feature reached through `call` or `callonce` runs **all** of its scenarios, environment tags and `@ignore` alike — the caller asked for that feature, so Karate does not second-guess the request. This is the same principle that skips the config chain for a called feature: environment steering is a property of the **run**, applied once at the entry point, not something re-decided at every call boundary. Practical consequences: 1. **`@env=` is not a safety interlock.** A destructive scenario tagged `@env=dev` still executes if some other feature `call`s it. 2. **`@ignore` plus a call tag is the idiom** for a scenario meant only to be called — the environment tag does not do that job. 3. **A reusable feature should not carry environment tags at all.** They will be silently ignored where it matters most, which is worse than not having them. ## Using them well - Keep the tag values identical to the `karate.env` values and to the `karate-config-<env>.js` suffixes. Three spellings of the same environment is a bug waiting to happen. - Prefer `@envnot=prod` over `@env=dev,qa,staging,perf` when the intent is "everywhere except production" — the list form silently excludes any environment someone adds later. - Expect the unset case in local development. Either give developers a documented `-Dkarate.env=local` or use `@envnot=` so a bare run still exercises the scenarios. - Report skipped counts in CI. An environment misspelling turns into scenarios that quietly do not run, and a pass on an empty selection looks exactly like a real pass. ## Where the tags may sit An environment tag can be written above a `Scenario` or above the `Feature`. A tag on the feature applies to every scenario in it: Karate computes each scenario's **effective tags** by merging the feature's tags with the scenario's own, de-duplicated, and selection reads that merged set. So a feature-level `@envnot=prod` covers the whole file, and a scenario inside it can still add its own narrower `@env=dev,local` on top. Both tags apply on top of each other in the obvious way — the scenario must satisfy every environment condition in its effective set. A feature-level `@envnot=prod` and a scenario-level `@env=dev` together mean "dev only, and certainly not prod", which is redundant but harmless. ## How this fits the rest of the environment story It is worth holding the three environment mechanisms apart, because they read the same value and do completely different things: | Mechanism | Reads | Does | |---|---|---| | The environment-specific config file | `karate.env` | adds a final set of config overrides | | `karate.env` in a config file or step | `karate.env` | lets your own code branch on the name | | `@env=` / `@envnot=` | `karate.env` | decides whether a scenario is selected at all | Setting the environment does the first two automatically. The third only happens where you have written a tag, and it is the only one of the three that can make a scenario disappear from a run without any output saying so.
- A Karate scenario tagged `@env=dev` did not run locally and nobody had changed it. What is the first thing to check?Whether `karate.env` was set for that run. With nothing set the value is `null`, it matches no name, and every `@env=`-tagged scenario is skipped without a warning. The report shows a smaller selection, not a failure, so the run still looks green.
- Can you rely on `@env=dev` to stop a destructive Karate scenario from running against production?No. It is a selection filter at the top level, and a feature reached through `call` runs all its scenarios regardless of environment tags. Treat the tag as a way to shape a run's contents and put a real guard — an explicit check on the resolved target inside the scenario — where the consequence actually matters.
saying these in an interview costs you the question
- Says an @env= tag runs the scenario when nothing is set
- Thinks @env= composes into an and/or/not tag expression
- Treats @env= as a guard against running in production
- Assumes environment tags filter called features too
- Believes @env= itself selects which config file loads