This product is not supported for your selected Datadog site. ().
Optimize the planning step
Test Parallelization adds a planning step that discovers tests before execution. Keep this step lightweight so the time saved by parallel execution is not offset by planning overhead.
Preinstall system dependencies with Docker
If your tests need operating system packages, include them in a CI base image instead of installing them during every CI run.
Discovery does not execute tests, so database setup, migrations, seeds, and fixtures are often unnecessary during the planning step.
During discovery, DD_TEST_OPTIMIZATION_DISCOVERY_ENABLED is set to 1. Use this variable to skip expensive setup code during planning.
For example, in Rails:
# in seeds.rbreturnifENV["DD_TEST_OPTIMIZATION_DISCOVERY_ENABLED"].present?# your seeds here# in rails_helper.rbActiveRecord::Migration.maintain_test_schema!unlessENV["DD_TEST_OPTIMIZATION_DISCOVERY_ENABLED"].present?RSpec.configuredo|config|unlessENV["DD_TEST_OPTIMIZATION_DISCOVERY_ENABLED"].present?config.use_transactional_fixtures=trueelseconfig.use_transactional_fixtures=falseconfig.use_active_record=falseendend
After these changes, test discovery can run faster and avoid failures when the database is unavailable during planning.
Cache test discovery
If full test discovery takes too long, cache the ddtest discovery file between CI runs. Restore your CI cache before planning, and pass the restored file to ddtest:
DD_TEST_OPTIMIZATION_RUNNER_TEST_DISCOVERY_CACHE=.ddtest-cache/tests-discovery.json ddtest plan
After planning, save the refreshed internal discovery file back to your CI cache:
ddtest invalidates the cache when any test file changes. The set of test files is determined by --tests-location and --tests-exclude-pattern.
Use suite-level skipping for Ruby
If Ruby test discovery remains a bottleneck after applying these optimizations, configure Test Impact Analysis to use suite-level skipping. This mode lets ddtest plan use test file discovery instead of discovering every individual test. It trades test-level skipping precision for lower planning overhead because Test Impact Analysis skips or runs an entire suite.
Suite-level skipping requires datadog-ci >= 1.34.0. Set DD_TESTOPTIMIZATION_TIA_TEST_SKIPPING_MODE=suite for both planning and test execution:
DD_TESTOPTIMIZATION_TIA_TEST_SKIPPING_MODE=suite ddtest plan
DD_TESTOPTIMIZATION_TIA_TEST_SKIPPING_MODE=suite ddtest run
If you execute tests with another command, set the same environment variable for that command. In CI workflows that plan and run tests in separate jobs, set the variable in both jobs.
Configure pytest
ddtest runs pytest as python -m pytest by default and appends the selected test files. For versions 1.7.0 and later, set --command to override the base command. For example, --command pytest runs the pytest console script instead of python -m pytest. ddtest runs <command> <files> and does not add -m pytest. It appends --ddtrace to PYTEST_ADDOPTS, preserving any existing value, so the ddtrace pytest plugin loads without changing your pytest config. To pass extra pytest flags without changing the base command, use PYTEST_ADDOPTS.
For test discovery, ddtest reads testpaths and python_files from pytest.ini, pyproject.toml, tox.ini, or setup.cfg. If no pytest config defines those settings, ddtest uses **/{test_*,*_test}.py.
During discovery, DD_TEST_OPTIMIZATION_DISCOVERY_ENABLED is set to 1. Use this variable to skip expensive setup code during planning, similar to skipping database setup during discovery.
Configure JavaScript frameworks
ddtest uses the local framework executable under node_modules/.bin when available and otherwise uses npx.
Use --command when your project invokes the framework through another package manager, a wrapper, a profile, or a non-default configuration. The command must invoke the selected framework directly. Do not include a -- separator. For Jest, Vitest, Mocha, and Cypress, omit test files because ddtest provides the files assigned to each worker. Cucumber.js paths and Playwright positional filters can restrict discovery, but ddtest replaces them during execution.
ddtest prepends -r dd-trace/ci/init to NODE_OPTIONS for worker processes unless it is already present. The dd-trace package must be resolvable from the project where ddtest runs. Complete the Test Optimization setup for your framework.
Cucumber.js
Use a command that invokes cucumber-js directly when selecting profiles or passing Cucumber filters:
bin/ddtest run --platform javascript --framework cucumber --command "pnpm exec cucumber-js --profile ci --tags=@smoke"
During planning, ddtest performs a serial dry run and uses Cucumber Messages to discover feature files. It includes only files containing scenarios selected by the effective paths, profile, tags, and name filters. Cucumber loads support code, but does not execute step or hook bodies. During execution, ddtest replaces positional feature paths and rerun files in --command with the files assigned to each worker while preserving Cucumber options. Prefer tag or name filters over scenario line selectors because ddtest plans at feature-file granularity.
Cypress
Use a command that invokes Cypress directly when selecting component testing, an alternate project root, or a custom configuration file:
bin/ddtest run --platform javascript --framework cypress --command "pnpm exec cypress run --project apps/web --component"
ddtest asks Cypress to resolve its effective configuration during planning and replaces any command-level --spec value with the files assigned to each worker during execution. Cypress calls the project’s setupNodeEvents function while resolving configuration, so side effects in that function also occur during planning. Cypress requires manual Test Optimization instrumentation.
Jest
ddtest runs Jest through the local node_modules/.bin/jest executable when it exists, or through npx jest otherwise. Use --command when your project runs Jest through a package manager or wrapper:
bin/ddtest run --platform javascript --framework jest --command "pnpm jest --runInBand"
ddtest discovers and splits test files and suites, not individual Jest tests.
Mocha
Use a command that invokes Mocha directly when passing framework options:
ddtest reads Mocha’s effective configuration without loading test modules during discovery. During execution, it replaces configured spec inputs with the files assigned to each worker and preserves shared --file setup.
Playwright
Use a command that invokes playwright test directly when selecting a configuration, projects, or other Playwright options:
bin/ddtest run --platform javascript --framework playwright --command "pnpm exec playwright test --config apps/web/playwright.config.ts --project chromium"
Do not include Playwright’s --shard option. ddtest asks Playwright to list tests with its effective configuration, deduplicates files shared by multiple projects, and passes each worker only its assigned files. Configuration, project, grep, and positional filters are preserved during discovery. Playwright loads test modules and their top-level code while listing tests, but does not run test bodies. During execution, ddtest preserves configuration, project, grep, reporter, retry, and worker options, replaces positional filters, and removes interactive UI options because workers run non-interactively. Playwright remains responsible for running dependency and teardown projects associated with the selected projects.
Vitest
Use --command when your project uses a package manager or Vitest projects:
bin/ddtest run --platform javascript --framework vitest --command "pnpm exec vitest run --project unit*"
The command must invoke Vitest directly. During planning, ddtest changes the run subcommand to list --filesOnly --json on Vitest 2.0 or later. On Vitest 1.6, ddtest uses Vitest’s config-aware discovery API. During execution, it appends the selected test files.
Configure Minitest in non-Rails projects
For non-Rails Minitest projects, ddtest uses bundle exec rake test and passes selected files in the TEST_FILES environment variable. Configure your Rake::TestTask to read TEST_FILES: