Scheduled Tasks

Cron, Intervals & Timeouts — Declared

Scheduled Tasks

@nestjs/schedule lets you annotate methods with @Cron, @Interval, or @Timeout — no external scheduler required.

4 min read Level 2/5 #nestjs#scheduling#cron
What you'll learn
  • Install @nestjs/schedule and register ScheduleModule.forRoot
  • Use @Cron, @Interval, and @Timeout decorators
  • Manage dynamic schedules through SchedulerRegistry

For periodic in-process work — nightly cleanups, hourly metrics, polling external APIs — @nestjs/schedule is the simplest tool that gets the job done. It is a thin wrapper around cron and node timers, but DI-friendly.

Setup

npm i @nestjs/schedule
import { Module } from '@nestjs/common';
import { ScheduleModule } from '@nestjs/schedule';

@Module({
  imports: [ScheduleModule.forRoot()],
})
export class AppModule {}

Cron, Interval, Timeout

import { Injectable, Logger } from '@nestjs/common';
import { Cron, Interval, Timeout } from '@nestjs/schedule';

@Injectable()
export class TasksService {
  private readonly logger = new Logger(TasksService.name);

  @Cron('0 0 * * *', { name: 'midnight-cleanup' })
  cleanup() {
    this.logger.log('Running nightly cleanup');
  }

  @Interval(60_000)
  poll() {
    this.logger.debug('Polling upstream');
  }

  @Timeout(5_000)
  warmup() {
    this.logger.log('Warming caches');
  }
}

The cron expression follows standard 5-field syntax (min hour dom month dow). Use named expressions like CronExpression.EVERY_HOUR to avoid typos.

Dynamic Schedules

For schedules that depend on runtime data (per-tenant, per-user), inject SchedulerRegistry:

import { Injectable } from '@nestjs/common';
import { SchedulerRegistry } from '@nestjs/schedule';
import { CronJob } from 'cron';

@Injectable()
export class DynamicJobs {
  constructor(private registry: SchedulerRegistry) {}

  add(name: string, cron: string, work: () => void) {
    const job = new CronJob(cron, work);
    this.registry.addCronJob(name, job);
    job.start();
  }

  stop(name: string) {
    this.registry.deleteCronJob(name);
  }
}

When To Pick Queues Instead

Schedules are great for in-process work that finishes quickly. If the work is heavy, retryable, or distributed across nodes, schedule the trigger but do the actual work via a BullMQ queue.

Unit Testing With Jest →