node-cron
Zero-dependency cron job scheduling for Node.js with overlap prevention and distributed coordination
Repository Health
Technical Analysis
node-cron is a zero-dependency, TypeScript-first job scheduling library for Node.js. It lets applications run recurring tasks using standard cron syntax (with optional second-level precision) while adding production-grade guardrails that plain cron expressions don’t provide on their own.
Beyond basic scheduling, node-cron adds overlap prevention so long-running jobs don’t stack when a tick fires before the previous run finishes, distributed coordination so only one instance of a horizontally-scaled app executes a given scheduled job, and the ability to run heavy jobs in an isolated forked process so they never block the event loop. Every task exposes a consistent runtime-control interface (start, stop, destroy, inspect) and emits lifecycle events for observability.
What You Get
- Standard cron syntax parsing with optional seconds field and Quartz-inspired extensions (L, L-n, W, LW, #)
- Overlap prevention (
noOverlap) so a slow job’s next tick is skipped instead of stacking concurrent runs - Distributed coordination (
distributed: true) so only one instance of a multi-replica deployment executes a given scheduled job - Background task execution by forking an isolated child process from a file path, keeping heavy work off the main event loop
- A consistent per-task control API (start/stop/destroy/getStatus/getNextRun/lastRun) plus lifecycle events for observability
Common Use Cases
- Running nightly backups or maintenance jobs on a fixed schedule inside a Node.js service
- Coordinating a single scheduled job across multiple replicas of a horizontally-scaled app
- Offloading CPU-heavy periodic work (report generation, data exports) to a background process so it doesn’t block request handling
- Scheduling recurring API polling or cache-refresh tasks with second-level precision
Under The Hood
Architecture - The library is organized around a small set of composable modules under src/: time/ implements a standalone cron-pattern matcher (time-matcher.ts, matcher-walker.ts, day-of-month.ts, day-of-week.ts) that walks calendar fields to find the next matching instant, independent of any scheduling concerns; scheduler/ (runner.ts, plan-beat.ts) drives the actual tick loop and computes the next “beat” from the matcher; tasks/ wraps a scheduled callback (inline-scheduled-task.ts) or a forked background process (background-scheduled-task/) behind a shared scheduled-task.ts state machine (state-machine.ts) so both execution modes expose the same start/stop/destroy/introspection surface; and coordinator/ (run-coordinator.ts, env-var-run-coordinator.ts, ipc-run-coordinator.ts) implements the pluggable distributed-election logic that decides which instance actually executes a given tick. node-cron.ts is the thin public entry point that wires these pieces together behind cron.schedule().
Tech Stack - Written entirely in TypeScript (99% of the codebase) targeting Node.js >=20, with zero runtime dependencies — a deliberate design constraint reflected in package.json. The build pipeline uses Rollup (rollup.config.js) to produce dual ESM/CJS output (dist/node-cron.js / .cjs) plus generated .d.ts typings via rollup-plugin-dts. Linting is handled by ESLint 10 with typescript-eslint, and releases are automated via release-please-config.json.
Code Quality - Testing is thorough and colocated: 28 non-test source files are matched by 39 *.test.ts files (more test files than source files), covering edge cases like DST transitions (dst.test.ts, dst-fuzz.test.ts) and IPC coordination (ipc-run-coordinator.test.ts) explicitly. Tests run under Vitest with coverage (vitest run --coverage). Naming is consistent and descriptive (plan-beat.ts, state-machine.ts), and the state machine pattern for task lifecycle keeps execution states explicit rather than relying on ad hoc boolean flags.
API Design - The public surface is intentionally minimal: a single cron.schedule(expression, task, options) call returns a task object with a small, consistent method set (start, stop, destroy, getStatus, getNextRun, lastRun) and an event emitter interface for lifecycle observability. Advanced behavior (overlap prevention, distributed coordination, background execution) is opt-in via options rather than separate APIs, which keeps the common case simple while scaling to production concerns without a steep learning curve.
Used by 17 apps in this directory
Karakeep
Bookmarks Archiving
Self-hosted bookmark manager that captures links, notes, images, and PDFs with AI tagging, full-text search, and automatic archiving.
nango
Authentication · Automation · Developer Tools
Build product integrations with AI using 800+ APIs — auth, proxy, and TypeScript functions on production-grade infrastructure.
OneUptime
Monitoring
The complete open-source observability platform that replaces PagerDuty, Datadog, Sentry, and StatusPage with a single self-hostable system.
Papra
Bookmarks Archiving
Self-hosted document archiving with email ingestion, OCR full-text search, and pluggable storage — store once, find anything.
Plasmic
CMS · Design Tools · Low Code Platforms
The open-source visual builder that lets teams design React apps and websites with drag-and-drop while integrating seamlessly with your codebase.
QRev
AI Agents · CRM
Open source AI-first sales platform that replaces Salesforce with autonomous agents handling prospecting, outreach, and lead management at scale.
Rybbit
Analytics
Open-source, privacy-friendly web and product analytics with cookieless tracking, session replays, funnels, and real-time dashboards — a self-hostable alternative to Google Analytics.
Valmis
AI Agents
A security-focused, self-hostable AI agent platform for production work — agents run in isolated containers that access credentials only through a host-side proxy, so the AI itself never sees API keys or plaintext credentials.