TUBELESS v0.2.2

Comparison

Tubeless is an in-process typed DAG you import from TypeScript or run from a Bun CLI. It is not a hosted workflow engine, a job queue, or a warehouse scheduler.

Same job: local typed steps

These all run work in one process. The difference is how much graph, typing, and preview you get without writing it yourself.

Feature tubeless roll your own p-graph listr2
Typed step outputs through dependencies Yes If you write it No Weak (shared context)
Invalid graphs rejected at definition Yes No Partial No
Plan / preview without executing Yes No No No
Dry-run and write gates Yes If you write it No No
Declared targets and partial rerun Yes If you write it No No
Child pipelines and fan-out Yes If you write it No Nested tasks
Inspect / plan / graph / run CLI Yes (Bun) No No TTY task renderer
Local run history Optional SQLite or NDJSON No No No
Crash-resume the graph No (file checkpoints only) If you write it No No

Roll your own await / Promise.all is enough for two or three linear steps with no dry-run, no partial rerun, and no typed fan-out. p-graph is topo-order plus concurrency. listr2 is a terminal task list (pretty TTY, rollback), not a reusable typed data graph.

File checkpoints (openCheckpoint in tubeless/node) record an "already done" set for batch API work. They do not replay a crashed process the way a durable workflow engine does.

Different job

If you need… Use
Typed local DAG, plan, dry-run, write gates tubeless
Two or three awaits and failure is "throw and exit" roll your own
Pretty CLI spinners, not a typed data graph listr2
Survive process death, sleep for days, wait on humans Temporal, Inngest, Trigger.dev, or DBOS
Thousands of the same job with retries across workers BullMQ, pg-boss, or graphile-worker
Org-wide schedule, catalog, warehouse assets Airflow, Dagster, or dbt
Record-at-a-time streams Node streams or RxJS

Those last four can still call a tubeless pipeline. A queue worker or a durable step can run pipeline.runOrThrow(...) when the hard part inside the job is a gated, typed graph.

Need Composition Who drives the DAG Who survives process death
The graph must outlive the process, sleep for days, or wait on humans Host embedding: a Temporal workflow, Lambda handler, or queue worker calls pipeline.runOrThrow(...) and passes runId / parentRunId The engine The engine
Some steps run elsewhere; the rest stay local fromRemote: one opaque parent step per remote unit of work The tubeless process Only the remote job, not the parent PipelineRun

When tubeless is the wrong default

  • The pipeline must outlive the process. Use a durable engine as the orchestrator.
  • The unit of work is one item, tens of thousands of times. Queue the items.
  • The consumer is a data platform, not a TypeScript repo. Use the platform.
  • You need a stable 1.x API or Windows. This package is 0.1.0, and Windows is untested. The CLI runs through Bun; npx tubeless works wherever Bun is installed and otherwise prints Bun install instructions.