ScheduleModule brings recurring background tasks into your nestrs application without relying on the OS cron daemon or an external scheduler. It is backed by tokio-cron-scheduler and starts automatically when your app calls listen. Declare task handlers with #[cron("...")] or #[interval(ms)] on a #[schedule_routes] impl block, register the service as a provider, and import ScheduleModule::for_root().
ScheduleModule is designed for app-local tasks — work that belongs in the same process as your HTTP server. It is not a distributed scheduler. For durable, multi-instance job queues, see QueuesModule.
Enable the feature
Register ScheduleModule
Import ScheduleModule::for_root() and add your task provider to providers. The ScheduleRuntime is automatically exported by the module and manages the underlying scheduler lifecycle.
Declare scheduled tasks
Annotate an #[injectable] struct with #[schedule_routes] and mark individual async methods with #[cron("...")] or #[interval(ms)].
Starting the scheduler
The scheduler starts when NestApplication::listen (or listen_graceful) is called. Wire it all together in main:
ScheduleRuntime also implements on_application_shutdown, so it shuts the scheduler down cleanly when the process exits via listen_graceful.
Cron expressions
nestrs uses the six-field tokio-cron-scheduler format:
Interval tasks
#[interval(ms)] takes a millisecond count as a literal integer. Use it for tasks that should fire at a fixed rate rather than at wall-clock times.
ScheduleRuntime
ScheduleRuntime is the provider that owns the tokio_cron_scheduler::JobScheduler. You can inject it if you need to inspect or extend the scheduler at runtime, but most applications only interact with it indirectly through ScheduleModule::for_root().
Combining scheduled tasks with HTTP controllers
ScheduleModule and HTTP controllers live in the same module graph. Scheduled tasks can share providers — inject a CacheService or PrismaService into your TasksService the same way you would in a controller.
Troubleshooting