Comparison · vs Dagu

RunWisp vs Dagu: not every job needs a DAG.

Dagu orchestrates multi-step pipelines with dependencies, conditionals, and parameter passing. RunWisp schedules independent tasks and babysits long-running services. Different tools, different problems. Pick the one that matches your workload.

Verdict

Should you switch?

The 10-second version. Skim, decide, scroll down for the receipts.

Consider RunWisp if

  • Every job on your box is independent. No step B waits on step A's output.
  • You also need long-running services supervised alongside scheduled tasks.
  • Dedicated service supervision, coalesced alerts, and a TUI matter more than DAG edges.
  • You want per-run history with stdout/stderr captured automatically.
  • A TUI over SSH is part of your workflow.

Stay on Dagu if

  • Any of your jobs form a pipeline: extract then transform then load.
  • Steps pass outputs to downstream steps via parameters.
  • Conditional execution matters: skip step C if step B produced no rows.
  • You need the DAG visualization in the web UI to reason about your workflow.
  • You're building data pipelines, not running cron jobs.
Head to head

Yes / no, at a glance

Yes / no — and both columns win on something.

Capability Dagu RunWisp
Single binary, no deps ✓ ✓
Step dependencies (DAG) ✓core feature ✗
Conditional execution ✓preconditions ✗
Parameter passing between steps ✓output vars ✗
Cron scheduling ✓ ✓5/6-field + aliases
Long-running processes ~scheduled start / stop / restart ✓supervision + replicas
Run history per firing ✓ ✓SQLite rows
Captures stdout / stderr ✓ ✓
Retries with backoff ✓retryPolicy ✓constant / linear / exp
Failure notifications ✓Slack / Teams / email / Telegram / webhook ✓Slack / Discord / email / Telegram / webhook
Overlap / concurrency control ✓queues + catch-up policies ✓skip / queue / kill
Catch-up after downtime ✓window + queues ✓latest / all / skip
Timezone-aware scheduling ✓CRON_TZ ✓named DST behavior
Web UI ✓DAG graph view ✓run history + logs
TUI ✗ ✓
DAG visualization ✓ ✗
All self-host features in GPL build ✗SSO / RBAC / audit require paid license ✓
Config format ~YAML ~TOML
Trade-offs

Pros & cons

What Dagu does better

  • DAG execution is the whole point. Steps depend on each other, run conditionally, pass outputs downstream.
  • Preconditions let you skip or abort a step based on the output of a previous one.
  • The web UI renders the DAG as a graph. You can see which step failed and why the downstream steps never ran.
  • Parameters and templating let you build reusable workflow definitions.
  • Sub-DAG execution: one DAG can call another DAG as a step.
  • If your workload is a pipeline, Dagu was built for it. RunWisp was not.

What RunWisp adds

  • Dedicated service supervision alongside scheduled tasks: restart-on-failure backoff, graceful stop, and replicas.
  • DST handling as named behaviour: fall-back deduped, spring-forward shifted forward by the gap (02:30 runs at 03:30).
  • catch_up = 1 / N / 0 per task, without enabling a separate queue subsystem.
  • on_overlap = "skip" / "queue" / "kill" per task.
  • Coalesced failure notifications. Five flaps become one Slack message, not five.
  • runwisp tui streams run history and logs over SSH. No browser needed.
  • Simpler config for the simple case. If every job is independent, a flat TOML stanza per task is less ceremony than a YAML DAG.
The simple case

The simple case

Run a backup script. Dagu defines a single-step DAG. RunWisp defines a scheduled task. For one independent job, the DAG wrapper is ceremony.

backup.yaml (Dagu)
# backup.yaml: a single-step Dagu DAG
schedule: "0 3 * * *"
steps:
  - id: backup
    run: /usr/local/bin/backup.sh
runwisp.toml
# runwisp.toml
[tasks.backup]
cron = "0 3 * * *"
run  = "/usr/local/bin/backup.sh"
Production-grade

The version that runs in prod

A four-step ETL pipeline. Dagu expresses the dependency chain: extract, validate, transform, load. RunWisp can run the same four scripts, but they fire independently on the same schedule. If step order matters, Dagu is the right tool here.

etl-pipeline.yaml (Dagu)
# etl-pipeline.yaml: extract, transform, load with dependencies
schedule: "0 4 * * *"
params:
  - name: DATE
    default: "2026-09-10"
steps:
  - id: extract
    run: |
      /opt/etl/extract.sh "${params.DATE}"
      printf 'raw_file=%s\n' "/tmp/raw-${params.DATE}.csv" >> "$DAGU_OUTPUT_FILE"
    outputs:
      - name: raw_file
  - id: validate
    run: /opt/etl/validate.sh "${steps.extract.outputs.raw_file}"
    depends: extract
  - id: transform
    run: /opt/etl/transform.sh "${steps.extract.outputs.raw_file}"
    depends: validate
  - id: load
    run: /opt/etl/load.sh
    depends: transform
    retry_policy:
      limit: 3
      interval_sec: 30
runwisp.toml (flat, no deps)
# runwisp.toml: same four scripts, but no dependency chain
# RunWisp can't express "load depends on transform".
# If your ETL steps MUST run in order, keep Dagu.
# If they're truly independent, RunWisp is simpler:

[tasks.extract]
cron              = "0 4 * * *"
timeout           = "30m"
keep_runs         = 60
notify            = ["slack-ops"]
run               = "/opt/etl/extract.sh"

[tasks.validate]
cron              = "0 4 * * *"
timeout           = "10m"
keep_runs         = 60
run               = "/opt/etl/validate.sh"

[tasks.transform]
cron              = "0 4 * * *"
timeout           = "45m"
retry_attempts    = 3
retry_delay       = "30s"
retry_backoff     = "exponential"
keep_runs         = 60
run               = "/opt/etl/transform.sh"

[tasks.load]
cron              = "0 4 * * *"
timeout           = "20m"
retry_attempts    = 3
retry_delay       = "30s"
retry_backoff     = "exponential"
keep_runs         = 60
notify            = ["slack-ops"]
run               = "/opt/etl/load.sh"
Migration

Migration cheat sheet

Only migrate if your DAGs are actually independent jobs. If steps depend on each other, keep Dagu.

Dagu RunWisp
schedule: in the YAML cron = on each [tasks.*]
steps[].run run =
steps[].depends No equivalent. If jobs are independent, drop it. If not, keep Dagu.
outputs + $DAGU_OUTPUT_FILE No equivalent between tasks. Keep a pipeline on Dagu, or explicitly manage a shared file.
steps[].preconditions Check inside the script itself, exit non-zero to fail.
retry_policy.limit retry_attempts =
retry_policy.interval_sec retry_delay = + retry_backoff =
Dagu notification rule (global / workspace / DAG) notify = ["slack-ops"]
Dagu web UI (DAG graph) RunWisp web UI (flat run history) or runwisp tui
params: + ${params.NAME} Environment variables in env = { ... } or inline in the script
Gotchas

Gotchas

RunWisp does not do DAGs

This is the big one. If step B depends on step A finishing successfully, RunWisp cannot express that. Tasks fire on their own schedule, independently. Wrapping a pipeline in a single shell script works for simple chains but loses Dagu's per-step visibility, retry, and conditional logic. If you need a DAG engine, keep the DAG engine.

No parameter passing between tasks

Dagu's output: lets step A export a variable that step B reads. RunWisp tasks are isolated. The workaround is a shared file or environment variable, but that's on you to manage. If your workflow relies on output chaining, that's a reason to stay on Dagu.

Dagu can time long-running runs; RunWisp supervises services

Dagu can schedule start, stop, and restart times for a long-running workflow. RunWisp adds dedicated service semantics for unexpected exits: restart policies with backoff, graceful stop, and multiple instances. Pick RunWisp when the process must be kept alive, not merely started on a timetable.

Independent jobs get simpler config

If your Dagu DAGs are all single-step (one steps: entry, no depends:), the YAML wrapper adds ceremony. A flat [tasks.backup] stanza with cron = and run = is fewer lines and easier to scan.

FAQ

FAQ

When should I pick Dagu over RunWisp?
Whenever your jobs form a pipeline. If step B needs step A's output, if you want to skip step C conditionally, if you need to visualize the dependency graph, Dagu is the right tool. RunWisp schedules independent tasks. It is not a workflow engine and does not pretend to be.
Can I wrap a multi-step pipeline in one RunWisp task?
You can put a shell script that runs extract.sh && transform.sh && load.sh into a single run = field. It works, but you lose per-step visibility, per-step retry, conditional branching, and the DAG graph. For anything beyond two commands in sequence, a real DAG engine is the better choice.
Does RunWisp have any plans to add DAG support?
No. RunWisp is deliberately not a workflow engine. Tasks are independent by design. If you need DAGs, use Dagu, Airflow, Temporal, or another tool built for that problem. RunWisp focuses on doing the simple case well: scheduled independent tasks and long-running services.
Can I run Dagu and RunWisp on the same machine?
Yes. They don't share state, ports (unless you configure the same web UI port), or config files. Use Dagu for your pipelines and RunWisp for your independent cron-style tasks and services.
What does RunWisp do that Dagu doesn't?
Dedicated service supervision (restart with backoff, graceful stop, replicas), per-task catch-up and overlap policies, coalesced failure notifications, a TUI, and an all-features GPL self-hosted build. Dagu now also has CRON_TZ schedules, catch-up, queue controls, and broad notification routing, so those are not RunWisp-only features.
Is Dagu hard to set up?
Not at all. Dagu is also a single Go binary with no dependencies. The setup experience is similar. The difference is what you configure: Dagu wants YAML DAG files with steps and dependencies. RunWisp wants a TOML file with flat task and service stanzas. Pick the shape that matches your workload.
How do notifications compare?
Both support Slack, Telegram, email, and generic webhooks; Dagu also has Microsoft Teams, while RunWisp has Discord. RunWisp's distinct behavior is coalescing repeated flaps so a rapid failure burst becomes one alert. Choose by destination and alert semantics, not by assuming Dagu is email-only.
Which one uses less memory?
Both are lightweight Go binaries. RunWisp idles around 25 MB of RAM. Dagu is similarly lean. Neither will stress a 512 MB VPS. The choice should be about the workload shape, not resource usage.
Get started
GPL 3.0 · no accounts · free to self-host

Not every job needs a DAG. Some just need to run on time.

If your tasks are independent, a flat TOML stanza per job is all you need. Install the binary, write a schedule, watch it land in the dashboard.

Install in 30 seconds
curl -fsSL https://get.runwisp.com | sh