Cron jobs, defined in YAML.
CronYAML is a lightweight Node.js scheduler for running shell commands from a simple YAML file. It keeps the scheduler in the foreground and never modifies the system crontab.
Repository: github.com/NaoCoding/cronyaml
npm package: naocoding/cronyaml
Documentation: CronYAML documentation
npm install cronyamlCronYAML is an ESM-only package and requires Node.js 20 or newer.
npx cronyaml init
npx cronyaml validate
npx cronyaml runBy default CronYAML discovers cron.yaml in the current directory, followed by cron.yml, .cron.yaml, and .cron.yml.
version: 1
jobs:
backup:
schedule: "0 2 * * *"
command: "npm run backup"
timeout: "30m"
retry:
attempts: 3
delay: "10s"
concurrency:
policy: forbidInstead of a local command, a job can download and run a script from GitHub. The runtime is inferred from the file extension, and runtime can be set explicitly when needed:
jobs:
remote-backup:
schedule: "0 3 * * *"
source: "https://github.com/my-org/scripts/blob/main/backup.sh"
args: ["--full"]CronYAML downloads the script when the job runs. Remote jobs always download a fresh copy by default; set use-cached: true to allow fallback to a previous cached copy when downloading fails. Supported runtimes are bash, sh, node, python, and powershell. Prefer a URL pinned to a commit SHA for predictable execution, for example https://raw.githubusercontent.com/my-org/scripts/<commit>/backup.sh.
The repository includes three runnable examples:
- Basic local command and its heartbeat script.
- Remote GitHub script, which uses examples/remote/hello.js.
- Gmail OAuth sender, including its config and token helper.
- Google Forms response poller, which
prints recent respondent emails as JSON for
for_eachfollow-ups.
The remote example can be checked and run with:
npx cronyaml validate --file example.yaml
npx cronyaml exec hello_remote --file example.yaml
npx cronyaml run --file example.yamlFor the maintained guides, see the documentation site source, including the examples guide, CLI reference, and configuration reference. Release history is maintained in the release notes.
cronyaml init [--force] [--file <path>]
cronyaml validate [--file <path>]
cronyaml list [--file <path>]
cronyaml exec <job> [--file <path>]
cronyaml run [jobs...] [--file <path>]
Use --file to override discovery, for example cronyaml run --file config/jobs.yaml.
Required fields are version: 1, jobs, and exactly one of command or source. schedule is optional: omit it for a job that should only run through exec or a conditional follow-up. Jobs can also set cwd, env, enabled, timezone, timeout, retry, concurrency, args, if_success, and if_failed. Remote jobs additionally support runtime.
Relative cwd paths are resolved from the directory containing cron.yaml. The scheduler validates all enabled and disabled jobs before starting.
Environment variables are interpolated with ${NAME}. CronYAML loads .env next to cron.yaml; actual process environment variables take precedence.
version: 1
defaults:
timezone: Asia/Taipei
timeout: 10m
jobs:
report:
schedule: "0 9 * * 1-5"
command: "node scripts/report.js --url ${REPORT_URL}"
env:
NODE_ENV: productionUse if_success or if_failed to run another configured job after the current
job finishes. A follow-up can be a job name or an object with arguments and
parameters. args are appended to local commands or passed to remote scripts;
env and parameters are passed as environment variables to the follow-up.
Follow-up values support runtime templates such as {{ result.stdout }} and
{{ result.success }}. Use repeat when the source returns a count, or
for_each when it returns a JSON array:
jobs:
backup:
schedule: "0 2 * * *"
command: "npm run backup"
if_success:
job: report-backup
args: ["--source", "{{ result.jobName }}"]
parameters:
backup_status: "{{ result.success }}"
if_failed: notify-backup-failure
report-backup:
schedule: "* * * * *"
command: "node scripts/report.js"
notify-backup-failure:
schedule: "* * * * *"
command: "node scripts/notify.js"For example, a form job can return a JSON array and run one email job per response:
if_success:
job: send-email
for_each: "{{ result.stdout }}"
parameters:
response: "{{ item }}"
email: "{{ item.email }}"Treat configuration files and remote sources as executable code: CronYAML intentionally runs commands and downloaded scripts with the current user's permissions. Only use trusted YAML and GitHub sources.
docker build -t cronyaml .
docker run --rm -v "$(pwd)/cron.yaml:/app/cron.yaml" cronyamlimport { loadConfig, CronYamlScheduler } from "cronyaml";
const config = loadConfig("./cron.yaml");
const scheduler = new CronYamlScheduler(config);
scheduler.start();MIT