Skip to main content
The @talosjs/cron component runs background tasks on top of Bun’s native Bun.cron. You extend the abstract Cron class, declare a schedule with a readable string like "every 1 hours", and implement a handler() that runs on that schedule. Behind the scenes the schedule is converted to a crontab expression, so there is no external scheduler to operate.

What it does

Schedules read like English. You write "every 5 minutes" or "in 30 seconds" and the component converts that to crontab syntax for you. Each job is a class with three abstract methods (getTime(), getTimeZone(), and handler()). getTimeZone() is part of the contract, but the current Cron base class does not pass a timezone into Bun.cron; schedules therefore run in the server’s local time. You drive a job with start(), stop(), and isActive(), and you register it with @decorator.cron() so the container can resolve it.

How it works

A cron job is a class that extends Cron and implements its three abstract methods. When you call start(), the schedule from getTime() is converted to a crontab expression and registered with Bun.cron, which invokes your handler() on every tick. The schedule string has the shape "<prefix> <number> <unit>": So "every 5 minutes" runs repeatedly every five minutes. The in prefix is converted into a concrete crontab expression for the computed future date and time; because Bun.cron is recurring, it is not a true one-shot timer. An invalid format or a non-positive number throws CronException.

Decorator and usage

@decorator.cron()

Registers a cron class with the container. It accepts an optional scope (defaults to singleton). Decorate any class that extends Cron.
Resolve and control the job from the container:
getTimeZone() is still part of the interface, but the current base class does not apply it when starting the job:
Use the in prefix only when you want the helper to compute the next matching calendar time from a delay:

Exceptions

The component throws CronException when a schedule is malformed or a job fails to start. It carries a machine-readable key, a human-readable message, and a data object.

Running jobs reliably

Catch errors inside handler(). A throw there should not take down the scheduler, so wrap risky work and log what fails. Make handlers idempotent, since a run may overlap or repeat and the work has to stay safe to execute more than once. Match the interval to the work too: a long task on "every 1 minutes" can pile up if it can’t finish before the next tick. For time-sensitive jobs like reports and billing, remember that the current base class runs on the server’s local time even if getTimeZone() returns a value. Inject caches, databases, and loggers from the container rather than constructing them inside the handler. Use every for recurring work; in is only a scheduling convenience for computing a future crontab expression, not a true one-shot timer. And stop jobs you no longer need: stop() releases the timer, and isActive() tells you whether a job is still running.

CLI command

Scaffold a cron class and its test file with the generator. It writes the class under modules/<module>/src/crons/<Name>Cron.ts, registers it in the module’s cronJobs array, and installs @talosjs/cron if it is missing.
The generated class is a ready-to-fill stub with the schedule, timezone, and handler in place:
See cron:create for the full command reference.

Use with Claude and Codex

The generator ships a matching cron:create skill. It runs the scaffold and then guides your AI agent through completing the job: setting the schedule in getTime(), choosing a timezone, and implementing handler() with real logic. Initialize the skills once for your agent:
Then ask Claude in natural language. It maps the request to the generator, runs it, and fills in the implementation:
Prompt
For example, the prompt above maps to cron:create --name=CleanExpiredSessions, then sets the schedule and implements the handler() to remove expired sessions.