Configuring Jest Test Timeouts: Global and Per-Test Limits
Set a global Jest timeout with testTimeout and override individual tests using jest.setTimeout(), with verification steps and common pitfalls.
29 Jan 2026, 20:06 UTC

The problem and the useful answer
A Jest test that never resolves can hang a CI job indefinitely, while a timeout that is too tight turns occasional slow runs into flaky failures. CI here means continuous integration, the automated system that runs tests after code changes. Jest does not assume a safe default for every environment, so you must choose a ceiling yourself. The practical takeaway is to set a global timeout with the testTimeout option in your Jest configuration, then override it for individual tests or suites with jest.setTimeout() when a specific case needs more or less time.
Configure a global timeout in jest.config.js
The testTimeout property accepts milliseconds and applies to every test in the project unless overridden. Jest starts measuring when the test function begins and stops when the returned promise resolves or the done callback is invoked.
module.exports = {
testTimeout: 5000,
};
Place this file in your project root and run Jest from that directory. You need read access to the configuration file and execute permission on the Jest binary, typically node_modules/.bin/jest or the jest script in package.json.
Override the timeout for one test or suite
Call jest.setTimeout(ms) inside a test function, or in beforeAll or beforeEach, to change the limit for that scope. The call must happen before the asynchronous work begins; calling it inside a callback after the test has already started does not retroactively extend the deadline.
const slowOperation = () =>
new Promise((resolve) => setTimeout(resolve, 300));
test('completes within the global limit', async () => {
await slowOperation();
});
test('allows more time for a slow dependency', async () => {
jest.setTimeout(2000);
await slowOperation();
});
In this example, the global limit is five seconds. The first test relies on that default. The second test explicitly raises its allowance to two seconds, which is still below the global ceiling but demonstrates how a scoped override works. If you needed more than five seconds for one case, you would set jest.setTimeout() to a value higher than the global testTimeout.
How Jest measures the deadline
Jest measures from the start of the test function until asynchronous completion. Work that is never awaited and never signals done is still subject to the limit. If the deadline passes, Jest aborts that test, reports a timeout error, and marks the test as failed.
Choose a limit based on observed timing
There is no universal correct timeout. A unit test that touches only memory might complete in milliseconds, while an integration test that contacts a database may need seconds. Run your suite locally and note the slowest tests, then set the global ceiling above the typical maximum with room for CI variability. A common starting point is five seconds for unit tests and fifteen to thirty seconds for integration tests, but your own measurements matter more than any convention.
What happens when a test exceeds the timeout
When Jest aborts a test for exceeding the timeout, it prints an error message identifying the limit and stops that test immediately. Critically, afterEach and afterAll hooks do not run for a test that times out. If your cleanup logic depends on those hooks, a timeout can leave temporary files, database records, or network connections behind.
Limits and common mistakes
- Flaky CI from tight limits. A timeout that passes on a fast laptop may fail on a slower CI agent. Measure typical test duration before choosing a value, and allow headroom for garbage collection, container startup, and network variance.
- Calling
jest.setTimeout()too late. The override must be registered before the asynchronous work starts. Placing it inside asetTimeoutcallback or after anawaitdoes not change the already-running deadline. - Forgotten promises. Returning a promise that never resolves, or firing asynchronous work without awaiting it, still counts against the timeout. Jest cannot distinguish between a slow test and a forgotten
await. - Skipped teardown. Because
afterEachandafterAllare skipped on timeout, do not rely on them for cleanup that must run even when a test hangs. Consider explicittry/finallyblocks inside the test for critical cleanup.
Verify the behavior before you rely on it
Create a temporary test file to confirm the limit is active:
test('fails after the configured timeout', async () => {
await new Promise((resolve) => setTimeout(resolve, 200));
});
Run Jest with testTimeout: 100 in your configuration. The test should fail with a message indicating that the async callback was not invoked within the 100 ms limit. Then change the sleep to 50 ms and confirm the same test passes. This two-step check verifies that Jest is enforcing the configured ceiling in both directions, but it does not prove the value is appropriate for your real test suite.
Command checklist
| Item | Detail |
|---|---|
| Where to run | Terminal at the project root, where jest.config.js lives. |
| Permissions | Read and write access to project files; execute access to the Jest binary. |
| Placeholder | Replace 5000 with your chosen limit in milliseconds. |
| Expected check | A test that sleeps longer than the limit fails; one that resolves sooner passes. |
| Risk | Too low a value causes intermittent failures on slower machines; skipped hooks can leave state behind. |
Rollback
Changing jest.config.js modifies project state. To roll back, restore the previous timeout value or remove testTimeout to return to Jest's default behavior, then re-run the affected tests to confirm they pass at the earlier limit.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.