Configuration

December 26, 2025 ยท View on GitHub

You are reading the documentation in the main development branch, which might contain some unreleased features. See documentation for older versions if you need it.


Configuration

Files

You can keep your configuration in a file. Cucumber will look for one of these files in the root of your project, and use the first one it finds:

  • cucumber.json
  • cucumber.yaml
  • cucumber.yml
  • cucumber.js
  • cucumber.cjs
  • cucumber.mjs

You can also put your file somewhere else and tell Cucumber via the --config CLI option:

cucumber-js --config config/cucumber.json

Here's a concise example of a configuration file in JSON format:

{
  "default": {
    "parallel": 2,
    "format": ["html:cucumber-report.html"]
  }
}

And the same in YAML format:

default:
  parallel: 2
  format:
    - "html:cucumber-report.html"

And the same in JavaScript (ESM) format:

export default {
  parallel: 2,
  format: ['html:cucumber-report.html']
}

And the same in JavaScript (CommonJS) format:

module.exports = {
  default: {
    parallel: 2,
    format: ['html:cucumber-report.html']
  }
}

Cucumber also supports the configuration being a string of options in the style of the CLI, though this isn't recommended:

module.exports = {
  default: '--parallel 2 --format html:cucumber-report.html'
}

(If you're wondering why the configuration sits within a "default" property, that's to allow for Profiles.)

TypeScript

You can also write your configuration file in TypeScript, with a .ts, .mts or .cts extension. These files are loaded with Node.js built-in TypeScript support, which has several caveats and limitations, mostly that your tsconfig.json won't be honoured and that you need to be explicit about type imports. Here's an example:

import type { IConfiguration } from '@cucumber/cucumber'

export default {
  parallel: 2,
  format: ['html:cucumber-report.html']
} satisfies Partial<IConfiguration>

Options

These options can be used in a configuration file (see above) or on the CLI, or both.

  • Where options are repeatable, they are appended/merged if provided more than once.
  • Where options aren't repeatable, the CLI takes precedence over a configuration file.
NameTypeRepeatableCLI OptionDescriptionDefault
pathsstring[]Yes(as arguments)Paths to where your feature files are - see below[]
backtracebooleanNo--backtrace, -bShow the full backtrace for errorsfalse
dryRunbooleanNo--dry-run, -dPrepare a test run but don't run it - see Dry Runfalse
forceExitbooleanNo--exit, --force-exitExplicitly call process.exit() after the test run (when run via CLI) - see CLIfalse
failFastbooleanNo--fail-fastStop running tests when a test fails - see Fail Fastfalse
formatstring[]Yes--format, -fName/path and (optionally) output file path of each formatter to use - see Formatters[]
formatOptionsobjectYes--format-optionsOptions to be provided to formatters - see Formatters{}
importstring[]Yes--import, -iPaths to where your support code is[]
languagestringNo--languageDefault language for your feature filesen
loaderstring[]Yes--loader, -lModule specifiers for loaders to be registered ahead of loading support code - see Transpiling[]
namestringNo--nameRegular expressions of which scenario names should match one of to be run - see Filtering[]
orderstringNo--orderRun in the order defined, or in a random order - see Filtering and Orderingdefined
parallelnumberNo--parallelRun tests in parallel with the given number of worker processes - see Parallel0
pluginstring[]Yes--pluginPaths or package names of plugins to load - see Plugins[]
pluginOptionsobjectYes--plugin-optionsOptions to be provided to plugins - see Plugins{}
publishbooleanNo--publishPublish a report of your test run to https://reports.cucumber.io/false
requirestring[]Yes--require, -rPaths to where your support code is, for CommonJS - see below[]
requireModulestring[]Yes--require-moduleNames of transpilation modules to load, loaded via require() - see Transpiling[]
retrynumberNo--retryRetry failing tests up to the given number of times - see Retry0
retryTagFilterstringYes--retry-tag-filterTag expression to filter which scenarios can be retried - see Retry
shardstringNo--shardRun a subset of scenarios across multiple test runs - see Sharding
strictbooleanNo--strict, --no-strictFail the test run if there are pending stepstrue
tagsstringYes--tags, -tTag expression to filter which scenarios should be run - see Filtering
worldParametersobjectYes--world-parametersParameters to be passed to your World - see World{}

Finding your features

By default, Cucumber finds features that match this glob (relative to your project's root directory):

features/**/*.{feature,feature.md}

If your features are somewhere else, you can override this by proving your own glob or directory:

  • In a configuration file { paths: ['somewhere-else/**/*.feature'] }
  • On the CLI cucumber-js 'somewhere-else/**/*.feature' (note that the argument is quoted - this is to avoid your shell expanding the glob itself which might lead to different behaviour than what's documented here)

This option is repeatable, so you can provide several values and they'll be combined, whilst maintaining the order you provided them in.

For more granular options to control which scenarios from your features should be run, see Filtering.

Finding your code

By default, Cucumber finds support code files with this logic:

  • If the features live in a features directory (at any level)
    • features/**/*.@(js|cjs|mjs)
  • Otherwise
    • <DIR>/**/*.@(js|cjs|mjs) for each directory containing the selected features

If your files are somewhere else, you can override this by proving your own glob, directory or file path to the import configuration option:

  • In a configuration file { import: ['somewhere-else/support/*.js'] }
  • On the CLI cucumber-js --import somewhere-else/support/*.js

Once you specify any import options, the defaults described above are no longer applied. The option is repeatable, so you can provide several values and they'll be combined, meaning you can load files from multiple locations.

The default behaviour and the import option both use the new ES modules API to load your files. This should work fine for the majority of cases, but sometimes (e.g. when transpiling with the require-module option), you'll need to use the require option instead in the same way, and they'll be loaded with the legacy CommonJS modules API.