In Cypress, if `defaultCommandTimeout` is set at the root and in the `e2e` block, which wins?
answer
- One flat configuration per run
- The file is not read as written
- Blocks are spread over the root
- The more specific site wins
- The other testing type's block is dropped
basics
~20 sThe e2e block wins. Before the run starts, Cypress flattens the configuration for the testing type it is launching by spreading that block over the root object, so a key declared in both takes the block's value.
solid answer
~40 sCypress resolves one flat configuration per run, for one testing type. It fills in defaults, then spreads the `e2e` or `component` block over the root object, so a key present in both ends up with the **block's** value — and the other type's block is discarded. That makes the root a shared default and each block a per-type override. With `defaultCommandTimeout: 4000` at the root and `12000` under `e2e`, e2e specs get 12000 and component specs get 4000. The spread is shallow, so an object-valued key such as `retries` is replaced wholesale rather than deep-merged. By the time a spec runs, the `e2e` and `component` keys no longer exist: `Cypress.config('defaultCommandTimeout')` returns the flattened number, and `cypress open` shows the same resolved value with a marker for where it came from.
go deeper
Recall the direction: the testing-type block overrides the root, not the other way round. That single fact resolves most confusion about a timeout that is not the number you read in the file.
Be ready to describe the resolution mechanically — defaults, then root, then the block for the running testing type spread over it, then the blocks deleted — and to say what a spec actually sees when it reads the value back.
Show that you debug this rather than guess: when a resolved Cypress value contradicts the file, you check whether the key is also declared in the block for the testing type in play, and you know the merge is shallow.
The tradeoff you own is duplication: which shared keys are stated once at the root, which genuinely earn a per-type value, and how a team keeps the two zones from drifting into two competing configurations.
## One run resolves one flat configuration The file you write is not the object your tests see. Before a run starts, Cypress resolves **one flat configuration for one testing type**. Three things happen in order: defaults are filled in, the testing-type block is spread over the root object, and both `e2e` and `component` keys are then deleted from the result. A spread is a last-writer-wins operation, so a key present in both places ends up with the **block's** value. That makes the two zones of the file mean something precise: - the **root** is a shared default, read by whichever testing type is running; - the **block** is a per-type override of that default; - the **other** type's block is thrown away entirely and can never affect the run. ```javascript module.exports = defineConfig({ defaultCommandTimeout: 4000, videosFolder: 'artifacts/videos', e2e: { baseUrl: 'https://staging.admin.example.com', defaultCommandTimeout: 12000, }, component: { defaultCommandTimeout: 2000, }, }) ``` | Run | `defaultCommandTimeout` | `videosFolder` | |---|---|---| | e2e | `12000` (from the `e2e` block) | `artifacts/videos` (from the root) | | component | `2000` (from the `component` block) | `artifacts/videos` (from the root) | ## What "the block wins" does and does not mean Two consequences are worth stating plainly, because both surprise people: 1. **The merge is shallow.** The block's value *replaces* the root's, it is not deep-merged into it. Declare `retries: { runMode: 2, openMode: 1 }` at the root and `retries: { runMode: 3 }` under `e2e`, and the e2e run gets the block's object, not a blend of the two. If you override an object-valued key in a block, restate the whole object. 2. **`e2e` and `component` do not survive into the browser.** By the time a spec executes, the flattening is done and both keys have been removed, so `Cypress.config()` returns a flat object with `defaultCommandTimeout` on it and no `e2e` key at all. Code that reaches for `Cypress.config('e2e')` in a spec gets `undefined`, not the block. ## The blocks have defaults of their own A detail that catches people editing a config for the first time: `e2e` and `component` are ordinary configuration keys with **their own default values**, not empty holes. `e2e` defaults to an object carrying the default `specPattern`, and `component` defaults to one carrying its `specPattern` and `indexHtmlFile`. Writing `e2e: {}` therefore does not mean "no e2e settings" — it means the e2e defaults, filled in as usual, then spread over the root. The practical consequence is that you never have to restate a default to keep it. Adding `e2e: { baseUrl: 'https://staging.admin.example.com' }` to a file that had no `e2e` block at all leaves spec discovery exactly where it was. What you cannot do is assume the block is inert: whatever is in it, defaults included, is applied over the root for the run. ## Where this sits among the other declaration sites The file's two zones are only the first two layers a value can come from. In order, later beating earlier for the layers that reach a spec: - the built-in default for the key; - the **root** of the config file; - the **testing-type block** for the run; - a suite- or test-level override object passed to `describe`, `context` or `it`, which is restored when that suite or test finishes; - `Cypress.config('key', value)` inside a spec, which lasts for the rest of that spec file. Opening the project shows the same picture: the Settings panel lists each resolved value and marks where it came from — a default, the config file, a `CYPRESS_`-prefixed environment variable, the command line, or `setupNodeEvents`. ## Practical consequences for a shared config For a multi-tenant admin console tested both end-to-end and at the component level, the working rule is to **state a shared key once at the root and repeat it in a block only where the difference is real**. A `defaultCommandTimeout` of 12000 makes sense for e2e specs that wait on a live tenant-settings page and is absurd for a mounted component, so that key earns its duplication. A `videosFolder` does not, and repeating it in both blocks only creates two places to edit. The failure this mechanic produces is quiet rather than loud. Nobody gets an error; they get a timeout that is not the number they read in the file, because they read the root and the block won. When a Cypress value does not match what the file appears to say, the first question is always: *is this key also declared inside the block for the testing type I am running?*
- Can a value in the `component` block affect a Cypress e2e run?No. Cypress flattens the configuration for exactly one testing type and then deletes both blocks from the result, so the other block's keys never reach a spec. `cypress run --e2e` and `cypress run --component` therefore resolve two different configurations out of the same file.
- Where do suite and test config overrides sit relative to the `e2e` block?After it. The flattened file value is the starting point for every spec; a config object passed to `describe`, `context` or `it` overrides it for that suite or test and is restored afterwards, and `Cypress.config()` inside a spec overrides it for the remainder of that spec file. Neither is written back to the file.
The root of the file is the house rule and each testing-type block is one team's local amendment: where the amendment is silent the house rule stands, and where it speaks it replaces the house rule for that run.
saying these in an interview costs you the question
- Says the root always beats the testing-type blocks
- Thinks both blocks are live during a single run
- Expects Cypress.config() to return a nested e2e object
- Assumes object-valued keys are deep-merged across zones