A lightweight, self-hosted workflow scheduler in a single Go binary — an open-source Apache Airflow / Azkaban alternative you can install with one command.
English · 简体中文
⭐ Star cronova on GitHub if it's useful — it helps other people find a lighter way to run their workflows.
cronova is a workflow scheduler and job orchestrator in the spirit of Airflow and Azkaban, built for teams who want DAG-based scheduling without the operational weight. It ships as one static Go binary with an embedded SQLite database — no JVM, no Python runtime, no external database, no message broker, no containers required. Install it on any Linux or macOS box with a single command, define your pipelines, and open the built-in web console.
The console task editor: build commands with click/drag variable pills (built-in, variables, connections, params).
# Install the scheduler + web console + native service on Linux or macOS, in one line:
curl -fsSL https://raw.githubusercontent.com/zoyluoblue/cronova/main/deploy/bootstrap.sh | sudo bash- 🟢 Small native install, zero service dependencies. Pure-Go, CGO-free scheduler + standalone executor with embedded SQLite (PostgreSQL optional for multi-instance setups).
curl | bashto install,cronova updateto upgrade,cronova uninstallto remove — no Airflow-style stack to babysit. Docker images and a compose stack included. - 🗂️ Airflow / Azkaban-style DAGs. Declarative YAML DAGs with dependency edges, cron /
@everyschedules, cross-DAG triggers and waits (trigger_after,depends_on_dag), sub-workflows, catchup / backfill, per-task retries & timeouts, resource pools, run priorities & serial execution policies, and trigger rules — the orchestration primitives you already know. - 📡 Scale out when you need to — dial-in workers. Remote workers join with a one-time token over mTLS and dial in (no inbound port, no shared filesystem, NAT-friendly); tasks route by
worker_group:, logs stream back live, and a worker restart re-adopts its running tasks instead of re-running them. Zero workers configured = the same single binary as always. - 🌐 Polyglot tasks + project upload. Every task runs as an OS subprocess, so write tasks in shell, Python, SQL, a JAR, or HTTP — any language on the host. Drag-and-drop a script, a whole project folder, or a
.zipin the console and cronova runs it in an isolated working copy. - 🤖 AI-native. A built-in Model Context Protocol (MCP) server and a remote JSON CLI let AI agents (Claude, and any MCP client) list, create, validate, trigger, and inspect DAGs through the same token-authenticated, role-gated API.
- 🛡️ Crash-recoverable execution. Run tasks in a decoupled gRPC executor so restarting or upgrading the scheduler never kills running jobs — on recovery it re-attaches to in-flight tasks with no double execution.
- 🖥️ Batteries-included web console. DAG dashboard, run history, task states, live log tailing (SSE), manual triggers, variables & connections, an audit trail, and a visual command editor — all served in-process. REST API + OpenAPI included.
cronova is an open-source, self-hosted workflow scheduler (a.k.a. job scheduler / task orchestrator / DAG scheduler) written in Go. It schedules DAGs — directed acyclic graphs of tasks — on cron or interval triggers, runs each task as a subprocess using the host's own interpreters, and gives you a web console, a REST API, a CLI, and an MCP endpoint for AI agents. Think of it as a cron replacement with dependencies, retries, backfill, and observability, or a lightweight Airflow alternative shipped as a compact native service pair.
# 1. Build (Go 1.26.5+) — or grab a prebuilt binary from Releases
go build -o cronova ./cmd/cronova
# 2. Start the scheduler + web console (in-process executor)
./cronova serve # console at http://localhost:8090
# 3. Drive it from the CLI (in another terminal)
./cronova dags # list DAGs from ./dags
./cronova trigger example_etl # run a DAG now
./cronova runs example_etl # run history + task statesOpen http://localhost:8090 for the console — DAG list, run history, task states, live logs, and one-click manual triggers.
The development default is unauthenticated but loopback-only. A non-loopback
bind is refused unless login is enabled or the explicit
-allow-unauthenticated-remote escape hatch is set. Use cronova init for a
new deployed instance; it enables authentication by default.
| cronova | Apache Airflow | Azkaban | plain cron | |
|---|---|---|---|---|
| Install | one archive / curl | bash |
Python stack + DB + broker | JVM + MySQL | built-in |
| Runtime deps | none (embedded SQLite) | Python, Postgres, Redis/Celery | Java, MySQL | none |
| DAGs & dependencies | ✅ | ✅ | ✅ | ❌ |
| Cron + interval + cross-DAG triggers | ✅ | ✅ | partial | cron only |
| Catchup / backfill | ✅ | ✅ | ❌ | ❌ |
| Retries, timeouts, pools | ✅ | ✅ | partial | ❌ |
| Crash recovery (no double-run) | ✅ | ✅ | partial | ❌ |
| Polyglot tasks (shell/Python/SQL/JAR/HTTP) | ✅ | ✅ (operators) | JVM-centric | any (no orchestration) |
| Web console + live logs | ✅ | ✅ | ✅ | ❌ |
| REST API + OpenAPI | ✅ | ✅ | partial | ❌ |
| AI agent / MCP integration | ✅ built-in | ❌ | ❌ | ❌ |
| Footprint | two small native processes, tens of MB | heavy | heavy (JVM) | tiny |
cronova targets the sweet spot between a bare crontab and a full Airflow deployment: real DAG orchestration with almost no operational overhead.
Drop a YAML file in ./dags/ (see dags/ for runnable examples):
dag_id: daily_etl
schedule: "0 2 * * *" # cron; or "@every 30s"; omit for manual-only
start_date: 2026-06-01
catchup: true # backfill missed periods
max_active_runs: 1
default_retries: 2
tasks:
- id: extract
type: shell
command: "python extract.py --date {{ logical_date }}"
pool: default
- id: transform
command: "python transform.py --date {{ logical_date }}"
deps: [extract]
- id: load
command: "psql -f load.sql"
deps: [transform]
retries: 3
timeout: 1800
trigger_after: # optional: run after another DAG succeeds
- dag_id: upstream_ingestTemplate variables work in any command, URL, header, body, or query:
{{ logical_date }}, {{ logical_datetime }}, {{ run_id }}, {{ dag_id }}, {{ task_id }}, {{ try_number }} (also injected as CRONOVA_* env vars), plus UI-managed {{ var.KEY }}, {{ conn.ID.host }}, and {{ params.KEY }}. In the console you don't type the {{ }} — a visual editor renders each variable as a color-coded pill and a grouped palette inserts them by click or drag.
Upload a single script, a whole project folder, or a .zip in the console (task editor → Project), then point a shell task at it:
tasks:
- id: run_main
type: shell
command: python3 main.py # runs with cwd = a clean copy of the project
project: my_appEach attempt gets a fresh isolated copy of the project as its working directory (CRONOVA_PROJECT_DIR points there), so re-uploads take effect next run and attempts never interfere. See docs/GETTING_STARTED.md.
Let an AI orchestrate cronova through the same token-authenticated, role-gated API — as native MCP tools or via the remote JSON CLI:
cronova tokens create my-agent -role admin # mint a token (local, once)
cronova mcp # MCP server over stdio (Claude, etc.)
export CRONOVA_SERVER=http://localhost:8090 CRONOVA_TOKEN=cnv_pat_…
cronova dags -o json # remote CLI, JSON output
cronova api POST /api/dags/validate '{"dag_id":"x","tasks":[…]}' # dry-run validatecronova mcp exposes ~30 catalog-derived tools (list_dags, create_dag, validate_dag, trigger_dag, get_task_log, retry_task, …); -read-only exposes just the reads. Guide + MCP config: docs/AGENTS.md.
cronova is a scheduler, not a runtime: it launches each task using the host's own interpreters (sh, python3, java, psql, …), Azkaban-style. Managed installs run a static scheduler plus a static standalone executor under systemd (Linux) or launchd (macOS), with no container or bundled runtime.
cronova start | stop | restart | status # manage the service (auto-elevates via sudo)
cronova update # fetch + install the latest release, then restart
cronova update v0.2.1 # pin/downgrade a specific version
cronova uninstall [--purge] # remove service + binary (--purge also deletes data)The one-line installer runs an interactive setup wizard (port, bind scope, admin account, auth). Full guide, the service-PATH gotcha, and crash-recoverable executor setup: docs/DEPLOY.md.
| Guide | What's inside |
|---|---|
| Getting Started | Install, first DAG, projects, template variables |
| Console Guide | Every page of the web UI — dashboard, task editor, runs & live logs, pools, tokens |
| DAG Reference | Every DAG/task field, task types, triggers, pools |
| CLI Reference | Every cronova command and flag |
| AI Agents (MCP) | MCP server, remote CLI, tokens, security |
| Deployment | systemd/launchd, updates, crash-recoverable executor |
| Architecture | Design rationale, execution model, diagrams |
| cronova vs Airflow | When to choose cronova, feature-by-feature |
| FAQ | Common questions, answered |
Is cronova an Airflow alternative? Yes — for teams who want DAG scheduling (dependencies, retries, catchup, pools, a web UI, a REST API) without running a Python stack, a separate database, and a message broker. cronova is a compact native service pair with an embedded database. For very large, plugin-heavy data platforms, Airflow remains the richer ecosystem.
Does cronova need a database, JVM, or Python? No. The scheduler and web console use an embedded SQLite database; the managed install adds a small standalone executor so scheduler restarts do not kill tasks. Python/Java/psql are only needed on the host if your tasks invoke them.
What languages can tasks be written in?
Any. Tasks are shell, python, sql, jar, or http; a shell task can invoke anything on the host (Node, Go, Rust binaries, …). The framework (Go) is fully decoupled from the task language.
How is cronova different from cron? cron runs isolated commands on a clock. cronova runs DAGs: tasks with dependencies, retries, timeouts, backfill, concurrency pools, cross-DAG triggers, a web console with logs, and an API — the things you end up hand-rolling around cron.
Can AI agents control cronova?
Yes. It ships a built-in MCP server (cronova mcp) and a remote JSON CLI, so AI agents can manage workflows through the same authenticated, role-gated API as humans.
Which platforms are supported? Linux and macOS, on both amd64 and arm64. Prebuilt binaries are on the Releases page.
Is it production-ready / crash-safe? Managed installs use the decoupled gRPC executor by default, so the scheduler can restart or upgrade without killing running jobs; on recovery it re-attaches to in-flight tasks with no double execution.
go test -race ./... # full test suite
# regenerate gRPC code after editing proto/ (needs: buf + protoc-gen-go[-grpc])
buf generate
# UI dev: serve console assets from disk (edit + reload, no rebuild)
CRONOVA_WEB_DIR=internal/web/static go run ./cmd/cronova serveContributions welcome — see the docs/ for architecture and design notes.
MIT © cronova authors.
Give it a star on GitHub — it's the simplest way to support the project and helps others discover a lighter way to run workflows.
cronova — self-hosted workflow scheduler · Airflow alternative · DAG orchestration · single Go binary · MCP-ready for AI agents.

