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 15 apps in this directory
Activepieces
Automation · AI Assistants
Open-source AI automation platform that converts 280+ workflow integrations into MCP servers for LLMs, with no-code builders and TypeScript extensibility.
Amical
Note Taking · AI Assistants
Local-first AI dictation that understands your active app — private, offline, and built for speed.
ChartBrew
Analytics · Databases
Open-source reporting platform to build live dashboards from SQL, NoSQL, APIs, and SaaS tools with an AI assistant that creates charts from natural language.
Enclosed
Security
Send end-to-end encrypted notes and files where the server never sees your content — true zero-knowledge sharing.
FastGPT
AI Agents · AI Development
Build, debug, and deploy knowledge-based AI agents with a visual workflow editor, RAG retrieval, and support for any OpenAI-compatible LLM.
Flowise
Developer Tools · Automation · No Code Platforms
Drag-and-drop visual builder for AI agents, RAG pipelines, and multi-agent systems—deploy anywhere in minutes.
FormBee
Forms Surveys
A self-hostable form backend that accepts HTML form submissions and routes them to email, Telegram, Discord, webhooks, and automation platforms — without writing any server-side code.
Joplin
Note Taking
The privacy-first, open-source note-taking app with end-to-end encrypted sync, AI assistance, and a powerful plugin ecosystem across every platform.
Karakeep
Bookmarks Archiving
Self-hosted bookmark manager that captures links, notes, images, and PDFs with AI tagging, full-text search, and automatic archiving.