Skip to content

Repository files navigation

Riverflow

Riverflow

A single-host workflow orchestrator.
Python-native. Airflow-shaped. Built to fit on one machine.


Why

Airflow without the cluster. No Kubernetes, no Celery, no external database, no worker fleet. One process, one host, one UI.

Use it for ETL, internal automation, scheduled jobs embedded in an application, or anything that fits on a VPS.

Install

pip install riverflow

Ten-line DAG

from datetime import timedelta
from riverflow import DAG, serve

with DAG(dag_id="hourly_rollup", schedule=timedelta(hours=1)) as dag:
    @dag.task("extract")
    async def extract(): ...

    @dag.task("transform")
    async def transform(): ...

    @dag.task("load")
    async def load(): ...

    extract >> transform >> load

serve(dag)

Open http://localhost:8083/ui.

The repository also includes a local showcase with two DAGs and a Flow that connects them:

uv run python src/main.py --open

For UI or API development, start a blank Riverflow with no registered workflows:

uv run python src/main.py --blank --open

Or skip the Python bootstrap entirely:

riverflow serve path/to/dags.py --open

For scripts and tests that just want to run a DAG once:

from riverflow import run
history = run(dag)
assert history.state.value == "success"

Flows

A DAG organizes tasks. A Flow organizes DAG runs without flattening their history, logs, schedules, or ownership boundaries.

from riverflow import DAG, Flow, serve

with DAG("ibge_extract") as extract:
    @extract.task("download")
    async def download(): ...

with DAG("medallion") as medallion:
    @medallion.task("promote")
    async def promote(): ...

with Flow("ibge_pipeline", schedule="0 3 * * *") as flow:
    source = flow.add_dag(extract, parameters={"scope": "ibge"})
    layers = flow.add_dag(medallion, parameters={"scope": "ibge"})
    source >> layers

serve(flow)

Each Flow node creates a normal DAG run with explicit parent Flow and node lineage. Independent branches run concurrently. A node can queue, reject, or force when its DAG is already running.

Features

Orchestration. Tasks compose into DAGs; DAG runs compose into Flows. Both support >> dependencies, schedules, trigger rules, and concurrent branches. DAG tasks also support retries and timeouts.

UI. A Broadsheet-flavoured single-page app. Overview, DAG detail (graph / overview / history / grid / gantt / tasks), run detail with live logs, and a built-in Host page for on-box CPU, memory, disk, and network — four charts in a 2×2 grid with a synchronised crosshair.

Live. WebSocket push — no polling, no full-page refreshes.

Keyboard. ⌘K command palette, / to filter, j / k to move, g d / g l / g h / g s to jump between sections.

Light footprint. Zero heavyweight chart libraries. Initial JS bundle ≈ 75 kB gzipped.

Shape of the code

src/riverflow/
├── core/        # DAG, Task, scheduler, executor, logging
├── models/      # Pydantic contracts shared with the UI
└── server/      # FastAPI app, WebSocket, host metrics collector
ui/              # React + Vite + Tailwind, served from the same process

Not goals

Horizontal scale-out. Multi-tenant auth. A plugin marketplace. If you need those, you need Airflow.

License

Apache 2.0

About

A lightweight, Python-native workflow orchestration library

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages