In-process cron for Bun and Node.

Give a job a name, a schedule and a function. Cronbake runs it to the second, won’t start it twice if the last run is still going, and keeps a record of what happened.

bun add cronbake
Second
0at :00
Minute
30at :30
Hour
909:xx
Day
*every day
Month
*every month
Weekday
1-5Mon to Fri
Next run in--:--:--Your local time
Upcoming runs
  1.  
  2.  
  3.  
  4.  
  5.  

What it looks like

  • Six fields or a preset. Use 0 30 9 * * 1-5 or @at_18:30. TypeScript rejects a preset it doesn’t recognise.
  • No pile-ups. If a run is still going when the next one is due, the new one is skipped and counted.
  • Failures stay contained. A callback that throws is caught and reported, and the job keeps its schedule.
  • You can see what happened. Every job keeps totals, average duration, its last error and recent runs.
scheduler.ts
import Baker from "cronbake";

const baker = Baker.create({
  onError: (error, job) => report(job, error),
});

baker.add({
  name: "send-digests",
  cron: "0 30 9 * * 1-5", // 09:30, Monday to Friday
  callback: async () => {
    await sendDigests();
  },
});

baker.add({
  name: "refresh-rates",
  cron: "@every_5_minutes",
  immediate: true, // also run once at startup
  callback: refreshRates,
});

baker.bakeAll();

// Later, from a health check or an admin page
baker.getStatus("send-digests"); // "running"
baker.nextExecution("send-digests"); // Date
baker.getMetrics("send-digests").failedExecutions; // 0

Where it fits

A long-running server or worker that has to do things on a schedule: clearing expired sessions, sending digests, refreshing a cache.

The package has no dependencies and comes to about 7 KB gzipped. There is nothing else to run.

Where it doesn’t

Serverless functions, since no process stays alive between requests. Several copies of the same app, unless you choose one to run the scheduler, because there is no distributed lock.

Work that has to happen no matter what. Missed ticks aren’t replayed and failed runs aren’t retried, so use a queue for that. More on running in production.

esc

Try overlap, restore or timezone.