clearInterval()
Stops a repeating timer created by setInterval() so it fires no further.
clearInterval(timeout)- Added in Node.js v0.0.1
Parameters
| Parameter | Type | Description |
|---|---|---|
$timeout | <Timeout> | <string> | <number> | A Timeout object as returned by setInterval() or the primitive of the Timeout object as a string or a number. |
Return value
<undefined>Nothing.
Errors
Does not throw for unknown, undefined or already-cleared values; it is a no-op.
clearInterval() stops a repeating timer. It takes the Timeout object returned by setInterval(), or that object's primitive value. Because both functions return the same Timeout class, clearTimeout() and clearInterval() are interchangeable in practice — but use the matching name so the intent reads correctly.
When to reach for it
- Ending a poll once the condition is met or an attempt budget runs out.
- Shutting down heartbeats and flush loops on
SIGTERMor in aclose()method. - Stopping a loop from inside its own callback — the usual place.
What trips people up
This is the call that decides whether your process can exit. An interval holds the event loop open indefinitely, so a missing clearInterval() shows up as a script that finishes its work and then hangs, or a test suite that never returns. If that is your symptom, look for an interval created in a module or a class constructor that nothing ever stops.
Store the handle where the stopping code can actually see it. Intervals created inside a callback or a loop iteration are easy to lose track of, and once the reference is gone the timer cannot be cleared at all — only killing the process stops it.
Clearing an already-stopped interval is a harmless no-op.
Example
When to use it
- Stop polling once a job reports it has finished
- Cap a retry loop at a maximum number of attempts
- Shut down a heartbeat when a connection closes
- Clear background timers so a test process can exit
Frequently asked questions
Why does my Node process hang after clearInterval?
Something else is still holding the event loop open — another interval, an open server or socket, or a pending timeout. Run node --trace-exit or inspect process.getActiveResourcesInfo() to see which handles remain.
Can I use clearTimeout to stop a setInterval?
Yes. setTimeout() and setInterval() both return the same Timeout class, so clearTimeout() and clearInterval() are functionally identical in Node. Using the matching name is purely a readability convention.
How do I stop an interval if I lost the returned handle?
You cannot — without the Timeout object or its primitive there is no way to reach the timer, and it repeats until the process exits. Always assign the return value of setInterval() to something the stopping code can see, such as a field on the owning object.
More examples
Polling with a hard attempt limit
Every branch that settles the promise also clears the interval. The attempts >= maxAttempts branch is the one people forget: without it a job stuck in 'pending' polls forever and the process can never exit.
function waitForJob(id, { every = 1000, maxAttempts = 30 } = {}) {
return new Promise((resolve, reject) => {
let attempts = 0;
const timer = setInterval(async () => {
attempts += 1;
try {
const job = await fetchJob(id);
console.log(`attempt ${attempts}: ${job.status}`);
if (job.status === 'succeeded') {
clearInterval(timer);
resolve(job);
} else if (job.status === 'failed') {
clearInterval(timer);
reject(new Error(`job ${id} failed`));
} else if (attempts >= maxAttempts) {
clearInterval(timer);
reject(new Error(`job ${id} still ${job.status} after ${attempts} polls`));
}
} catch (err) {
clearInterval(timer);
reject(err);
}
}, every);
});
}Clearing timers during graceful shutdown
Registering every interval in a Set means shutdown can clear all of them without tracking each handle by name. The final log line is literally true: once the last interval is cleared and no other handles remain, Node exits on its own without process.exit().
const timers = new Set();
function everyMs(fn, ms) {
const t = setInterval(fn, ms);
timers.add(t);
return t;
}
everyMs(() => console.log('heartbeat'), 5000);
everyMs(() => console.log('cache sweep'), 60_000);
function shutdown(signal) {
console.log(`${signal} received, clearing ${timers.size} timers`);
for (const t of timers) clearInterval(t);
timers.clear();
console.log('event loop is now empty; process will exit');
}
process.on('SIGTERM', () => shutdown('SIGTERM'));
process.on('SIGINT', () => shutdown('SIGINT'));A self-limiting interval that reports why it stopped
Shows the three ways a periodic task usually ends — the callback returns false, a deadline passes, or the caller invokes the returned cancel function — with each path clearing the same handle. Returning a cancel closure keeps the handle from leaking to callers who might misuse it.
function repeatUntil(fn, ms, deadlineMs) {
const started = Date.now();
let runs = 0;
const timer = setInterval(() => {
runs += 1;
const elapsed = Date.now() - started;
if (fn(runs) === false) {
clearInterval(timer);
console.log(`stopped by callback after ${runs} runs`);
} else if (elapsed >= deadlineMs) {
clearInterval(timer);
console.log(`stopped by deadline after ${runs} runs`);
}
}, ms);
return () => clearInterval(timer); // manual cancel
}
const cancel = repeatUntil((n) => n < 5, 100, 10_000);
process.on('SIGTERM', cancel);
Discussion