Retrying failed Detox tests reruns only the suite files that failed after the first mobile test pass. It is useful when simulator startup, device control, or short-lived app timing noise makes an otherwise passing end-to-end suite fail intermittently.
Detox exposes retry control through detox test with --retries for one run, or through testRunner.retries in .detoxrc.js when the same retry policy should apply in CI. The retry mechanism respawns the underlying runner, usually Jest, with the failed suite file paths instead of the original default test path list.
Keep the retry count small and treat a repeated failure after the last retry as a real failure to investigate. If the suite already uses jest.retryTimes(), Detox suppresses its own CLI retry layer by default so the same flaky test does not multiply run time unexpectedly.
Related: How to run Detox tests
Related: How to debug flaky Detox tests
$ detox test -c ios.sim.debug --retries 2 e2e/login.test.js There were failing tests in the following files: 1. e2e/login.test.js Detox CLI is going to restart the test runner with those files... DETOX_CONFIGURATION="ios.sim.debug" jest --config e2e/jest.config.js e2e/login.test.js PASS e2e/login.test.js
--retries 2 allows up to two reruns of failed suite files. If the retry passes, the final process status should be successful.
$ rg "retryTimes" e2e e2e/login.test.js:jest.retryTimes(2);
Keep jest.retryTimes() when the retry needs to happen inside a single test file. Use Detox retries when the whole failed suite file should be restarted with fresh app and runner setup.
describe('login flow', () => {
it('signs in with a saved account', async () => {
await element(by.id('email')).typeText('user@example.net');
await element(by.id('password')).typeText('ExamplePassw0rd!');
await element(by.id('sign-in')).tap();
await expect(element(by.id('home-screen'))).toBeVisible();
});
});
Do not publish real accounts, passwords, tenant names, or production endpoints in test fixtures or failure logs. Replace them with neutral values before sharing retry output.
/** @type {Detox.DetoxConfig} */
module.exports = {
testRunner: {
args: {
$0: 'jest',
config: 'e2e/jest.config.js',
_: ['e2e']
},
retries: 2,
noRetryArgs: ['shard', 'maxWorkers']
},
apps: {
// existing app definitions
},
devices: {
// existing device definitions
},
configurations: {
// existing Detox configurations
}
};
testRunner.noRetryArgs removes runner arguments that should not be reused when Detox narrows the retry to failed files. shard is removed by default; add project-specific worker or shard options only when they make retry runs invalid.
$ detox test -c ios.sim.debug e2e/login.test.js There were failing tests in the following files: 1. e2e/login.test.js Detox CLI is going to restart the test runner with those files... PASS e2e/login.test.js
testRunner: {
retries: 2,
jest: {
retryAfterCircusRetries: false
}
}
Leave retryAfterCircusRetries at false unless the project deliberately needs both jest.retryTimes() and Detox suite retries. Enabling both layers can make flaky suites run much longer.
$ detox test -c ios.sim.debug --retries 2 --record-logs failing --take-screenshots failing e2e/login.test.js FAIL e2e/login.test.js Detox test failed after 2 retry attempts. Artifacts saved to artifacts/ios.sim.debug.2026-06-18T12-00-00Z
A failure that survives the final retry should be debugged from logs, screenshots, and app state instead of hidden behind a larger retry count.
Related: How to debug flaky Detox tests