RunWisp vs Cronicle: two self-hosted schedulers with a web UI.
Both replace cron with a scheduler you can see: run history, live logs, retries, alerts. Cronicle is a Node.js app built for a fleet, with jobs defined in its UI. RunWisp is one Go binary per box, with jobs defined in a TOML file in git.
Should you switch?
The 10-second version. Skim, decide, scroll down for the receipts.
Switch to RunWisp if
- You want job definitions in git and reviewed in pull requests, not clicked into a UI.
- Installing and patching Node.js 22 just for a scheduler feels like a lot.
- You run on one VPS, a Pi or a Docker host, not a fleet.
- You also need long-running workers supervised, not just jobs scheduled.
- You want a TUI over SSH as well as the web UI.
- Cronicle's move to maintenance mode makes you want a scheduler that's still adding features.
Stay on Cronicle if
- You schedule across many servers, with failover if the primary dies.
- Several people log in with their own accounts and privileges.
- You chain jobs: run B after A succeeds, run C if it fails.
- You rely on CPU and memory limits that abort a runaway job.
- Creating events from the UI is how your team prefers to work.
Yes / no, at a glance
Yes / no — and both columns win on something.
| Capability | Cronicle | RunWisp |
|---|---|---|
| Web UI with live logs | ✓ | ✓ |
| Run history per job | ✓ | ✓ |
| Retries + delay | ✓up to 32 | ✓constant / linear / exp |
| Per-job timeout | ✓ | ✓ |
| Catch-up after downtime | ✓ | ✓ |
| Per-job timezone | ✓ | ✓ |
| Failure notifications | ✓email + web hook | ✓Slack / Telegram / Discord / ntfy / email / webhook |
| REST API | ✓ | ✓ |
| Jobs defined in a file in git | ✗UI / API, export for backup | ✓runwisp.toml |
| Single binary, no runtime | ✗Node.js 22+ | ✓ |
| Official Docker image | ✗ | ✓amd64 + arm64 |
| Long-running services | ✗ | ✓[services.*] |
| Seconds-level schedules | ✗1-minute resolution | ✓ |
| Terminal UI over SSH | ✗ | ✓ |
| Multi-server + failover | ✓primary / backup / workers | ✗one daemon per box |
| Multiple user accounts + privileges | ✓ | ✗one password |
| Chain reactions (job after job) | ✓ | ✗not a DAG engine |
| CPU / memory limits per job | ✓ | ~measured, not enforced |
| Plugins in any language | ✓ | ✗shell commands |
| Actively getting new features | ~fixes only; xyOps is the successor | ✓ |
Pros & cons
What Cronicle does better
- Built for many servers: a primary with automatic backup takeover, worker groups, and least-CPU or round-robin job placement.
- Multiplex runs one event on every server in a group at once.
- Real user accounts with per-user privileges, and API keys with their own.
- Chain reactions: start another event when a job succeeds or fails.
- CPU, memory and log-size limits that abort a runaway job, plus per-job resource graphs.
- Plugins in any language over JSON, and a built-in HTTP request plugin.
- Detached jobs keep running through a scheduler restart.
What RunWisp adds
- Jobs live in runwisp.toml: diffable, reviewable, and rebuilt from git if the box dies.
- One static Go binary, about 30 MB of RAM idle. No Node.js to install or patch.
- Supervises long-running services with restarts, backoff and health checks, in the same file as the schedule.
- Overlap policy beyond a concurrency cap:
on_overlap = "skip" | "queue" | "kill". - Fails a run that printed
ERRORbut exited 0, withfailures = ['+output:ERROR']. - Slack, Discord, Telegram, ntfy, Gotify, Pushover, email and webhooks built in, with repeats grouped during an outage.
- A TUI over SSH as well as a web UI that works on a phone.
- Official Docker image, Homebrew tap, and Compose-aware tasks that exec into your app's container.
The simple case
A nightly backup. Cronicle stores the event in its own storage, created from the Schedule tab or the API. RunWisp reads it from a file.
# Cronicle: the event lives in Cronicle's storage. Made in the UI,
# or POSTed to /api/app/create_event/v1 with an API key:
{
"title": "Nightly backup",
"enabled": 1,
"category": "general",
"plugin": "shellplug",
"target": "allgrp",
"timing": { "hours": [3], "minutes": [0] },
"params": { "script": "#!/bin/sh\n/usr/local/bin/backup.sh" }
} # runwisp.toml: in your repo, next to the code it runs
[tasks.nightly-backup]
cron = "0 3 * * *"
run = "/usr/local/bin/backup.sh" The version that runs in prod
The same backup, hardened. Most fields map one to one. Cronicle adds server placement and a chain to a cleanup event; RunWisp adds backoff, retention and a supervised worker in the same file.
{
"title": "Nightly backup",
"enabled": 1,
"category": "general",
"plugin": "shellplug",
"target": "allgrp",
"algo": "least_cpu",
"timezone": "Europe/Berlin",
"timing": { "hours": [3], "minutes": [0] },
"max_children": 1,
"catch_up": 1,
"timeout": 3300,
"retries": 2,
"retry_delay": 30,
"notify_fail": "[email protected]",
"web_hook": "https://hooks.slack.com/services/...",
"chain_error": "cleanup_event_id",
"params": { "script": "#!/bin/sh\n/usr/local/bin/backup.sh" }
} [tasks.nightly-backup]
description = "Snapshot the data volume off-site"
cron = "0 3 * * *"
timezone = "Europe/Berlin"
on_overlap = "skip"
catch_up = 1
timeout = "55m"
retry_attempts = 2
retry_delay = "30s"
retry_backoff = "exponential"
keep_runs = 60
notify = ["slack-ops", "email-ops"]
run = "/usr/local/bin/backup.sh"
[services.worker] # Cronicle doesn't supervise these
instances = 2
run = "node /app/worker.js" Migration cheat sheet
Cronicle event fields on the left, runwisp.toml on the right.
| Cronicle | RunWisp |
|---|---|
timing object | cron = "0 3 * * *" |
params.script (Shell Plugin) | run = |
timezone | timezone |
max_children | max_concurrent + on_overlap |
catch_up: 1 | catch_up = 1 (or N to replay up to N firings) |
timeout: 3300 (seconds) | timeout = "55m" |
retries + retry_delay | retry_attempts + retry_delay + retry_backoff |
notify_fail / web_hook | notify = ["email-ops", "slack-ops"] |
Event with no timing (on demand) | A task with no cron; run it from the UI, CLI or a hook token |
| API key to trigger a job | hook_tokens, scoped to one task |
chain / chain_error | No equivalent. Call the next step at the end of run, or use a workflow engine. |
target server group | No equivalent. Install RunWisp on each server that runs jobs. |
Gotchas
One box, one daemon
Cronicle can place a job on any server in a group and fail over to a backup primary. RunWisp has no cluster: each machine runs its own daemon with its own tasks and UI. If a job must run once across a fleet, whichever server is alive, keep Cronicle or look at a workflow engine.
No chains, on purpose
RunWisp tasks are independent. If job B must start when job A succeeds, put both in one run (a.sh && b.sh), or move to Dagu or Airflow. For a handful of chains, the shell is usually enough.
Cronicle's successor is xyOps
Cronicle's author now builds xyOps and has said Cronicle gets mainly bug fixes and security patches. xyOps imports Cronicle data and adds workflows and server monitoring. If you like Cronicle's model and want it maintained, look at xyOps before switching tools.
Your schedule becomes reviewable
In Cronicle, who changed a schedule and why is in the activity log, if anywhere. In RunWisp it's a diff in a pull request. runwisp reload validates the whole file before applying it, so a typo leaves the running config alone.
FAQ
What is a good Cronicle alternative?
Is Cronicle still maintained?
Can I import my Cronicle events into RunWisp?
Does RunWisp need Node.js?
Can several people use RunWisp?
Which uses fewer resources?
Put the schedule back in git.
Install the binary, write one runwisp.toml stanza per Cronicle event, and watch the first run land with its exit code and output.
curl -fsSL https://get.runwisp.com | sh