Skip to content

Node.js Timers and setImmediate — Complete Guide to Timer Scheduling

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Node.js Timers and setImmediate. We cover key concepts, practical examples, and best practices to help you master this topic.

Node.js timers schedule callback execution with setTimeout (one-time delay), setInterval (repeating), and setImmediate (check phase), each with distinct event loop placement.

What You'll Learn

By the end of this tutorial, you'll use setTimeout, setInterval, and setImmediate effectively, understand minimum delay behavior, cancel scheduled timers, and avoid common timing pitfalls.

Why Timers Matter

Timers control execution order, implement polling, schedule background tasks, and manage timeouts for external services. Misusing them causes race conditions and performance issues.

Real-World Use

An API Gateway uses setTimeout for request timeouts, setInterval for health check polling every 30 seconds, and setImmediate to defer processing after I/O callbacks.

Timer Learning Path

flowchart LR
  A[Event Loop Phases] --> B[Timers]
  B --> C[setImmediate]
  C --> D[nextTick]
  D --> E[Blocking vs Non-Blocking]
  B --> F{You Are Here}
  style F fill:#f90,color:#fff

setTimeout Basics

setTimeout schedules a callback to run after a minimum delay in milliseconds. The actual delay depends on event loop congestion.

console.log("Start");
const timerId = setTimeout(() => {
  console.log("Executed after ~100ms");
}, 100);
console.log("End - timer scheduled");
// Output:
// Start
// End - timer scheduled
// Executed after ~100ms

setInterval Repeating

setInterval schedules a callback to run repeatedly at the specified interval. The delay is between the start of each invocation.

let count = 0;
const intervalId = setInterval(() => {
  count++;
  console.log(`Interval tick ${count}`);
  if (count >= 3) {
    clearInterval(intervalId);
    console.log("Interval cleared");
  }
}, 500);
// Output (500ms apart):
// Interval tick 1
// Interval tick 2
// Interval tick 3
// Interval cleared

setImmediate Placement

setImmediate schedules a callback in the check phase, immediately after the poll phase completes. It runs before any timers scheduled with setTimeout(fn, 0).

const fs = require("node:fs");
fs.readFile(__filename, "utf8", () => {
  setImmediate(() => {
    console.log("setImmediate: runs after poll in check phase");
  });
  setTimeout(() => {
    console.log("setTimeout: runs in next timers phase");
  }, 0);
});
// Output:
// setImmediate: runs after poll in check phase
// setTimeout: runs in next timers phase

Unref and Ref

Unref allows a timer to not keep the event loop running. Ref restores the behavior. Useful for timers that should not prevent Process exit.

const timer = setTimeout(() => {
  console.log("This may not run if nothing else keeps the loop alive");
}, 1000);
timer.unref();
console.log("Timer unreffed - process may exit before it fires");
// Timer unreffed - process may exit before it fires

Clearing Timers

Always clear timers when they are no longer needed to prevent memory leaks and unexpected callbacks.

const timeout = setTimeout(() => console.log("Never runs"), 1000);
const interval = setInterval(() => console.log("Never runs"), 1000);
const immediate = setImmediate(() => console.log("Never runs"));
clearTimeout(timeout);
clearInterval(interval);
clearImmediate(immediate);
console.log("All timers cleared");

Common Mistakes

1. Assuming setTimeout(fn, 0) Is Instant

Minimum delay is 1ms (clamped from 0). It still waits for the timers phase.

2. Forgetting to Clear Timers

Uncleared timers keep the event loop alive and cause memory leaks. Always store timer IDs and clear on cleanup.

3. Nested setTimeout vs setInterval

Nested setTimeout guarantees delay between completions. setInterval does not account for execution time.

4. Using setInterval for Precise Timing

setInterval drift accumulates. Use recursive setTimeout for precise intervals by recalculating the delay.

5. Assuming setImmediate Is Faster Than setTimeout(fn, 0)

setImmediate runs in the check phase. setTimeout(fn, 0) waits for the timers phase. Inside I/O, setImmediate wins.

Practice Questions

1. What is the minimum delay for setTimeout?

1ms. Values less than 1 are clamped to 1. Older Node.js versions clamped to 4ms.

2. How does setInterval differ from recursive setTimeout?

setInterval schedules the next invocation based on start time. Recursive setTimeout schedules based on completion time.

3. What does unref() do on a timer?

It allows the process to exit even if the timer is still pending. The timer still fires if the loop is active.

4. In which event loop phase does setImmediate run?

The check phase, which runs immediately after the poll phase.

5. Challenge: Create a precise repeating timer using recursive setTimeout.

function preciseInterval(fn, delay) {
  let schedule = () => {
    fn();
    setTimeout(schedule, delay);
  };
  setTimeout(schedule, delay);
}
preciseInterval(() => console.log("Tick", Date.now()), 1000);

FAQ

What is the difference between setImmediate and setTimeout(fn, 0)?

setImmediate runs in the check phase after poll. setTimeout(fn, 0) runs in the timers phase. Inside I/O, setImmediate runs first.

Does setInterval account for callback execution time?

No. The interval is between start times. If the callback takes longer than the interval, they stack.

Can I pass arguments to timer callbacks?

Yes. setTimeout(fn, delay, arg1, arg2) passes arguments to the callback function.

What happens if I pass a string to setTimeout?

It is evaluated like eval(). Never pass strings. Always pass a function reference.

Is setImmediate available in browsers?

No. setImmediate is Node.js specific. Browsers use setTimeout(fn, 0) or postMessage patterns.

Mini Project: Timer-Based Polling System

Build a service that polls a resource with configurable intervals and timeout protection.

class Poller {
  constructor(url, intervalMs = 5000, timeoutMs = 30000) {
    this.url = url;
    this.intervalMs = intervalMs;
    this.timeoutMs = timeoutMs;
    this.timer = null;
  }
  start() {
    const poll = () => {
      console.log(`Polling ${this.url}...`);
      const timeout = setTimeout(() => console.log("Request timed out"), this.timeoutMs);
      timeout.unref();
      this.timer = setTimeout(poll, this.intervalMs);
    };
    this.timer = setTimeout(poll, 0);
  }
  stop() {
    clearTimeout(this.timer);
    console.log("Polling stopped");
  }
}
const poller = new Poller("https://api.example.com/health");
poller.start();
setTimeout(() => poller.stop(), 20000);

What's Next

Node.js process.nextTick Node.js Blocking vs Non-Blocking Node.js Error Handling

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro