Make vs Just vs Broski
This page answers one practical question: if your team already uses Make or Just, what changes when you move to Broski?
What problems Broski solves
Traditional task runners are excellent at command orchestration, but they leave core reliability gaps for modern CI and monorepos:
- timestamp-driven rebuild ambiguity (
makecan rebuild too much or too little) - low explainability for reruns (especially after env or argument changes)
- no transactional output safety (partial outputs after failed runs)
- no built-in deterministic content fingerprinting
Broski keeps simple task authoring while adding deterministic cache keys, explainability, and ACID-safe output promotion.
Same intent, different guarantees
Define a build task
- Broski
- Make
- Just
build [target] [mode="release"]:
@in src/**/* Cargo.toml
@out dist/{{ target }}
@requires cargo
cargo build --bin {{ target }} --{{ mode }}
build:
cargo build --release
build target mode="release":
cargo build --bin {{target}} --{{mode}}
Add a local dev task
- Broski
- Make
- Just
dev:
@mode interactive
npm run dev
dev:
npm run dev
dev:
npm run dev
Trigger with arguments
- Broski
- Make
- Just
broski build api debug
broski run build --explain
make build TARGET=api MODE=debug
just build api debug
Why teams choose Broski for CI
| Capability | Make | Just | Broski |
|---|---|---|---|
| Content hashing | No | No | Yes (BLAKE3) |
| DAG graph execution | Partial/manual | Basic | First-class |
| Interactive mode | Native | Native | Native |
| Cache explainability | No | No | --explain |
| ACID output promotion | No | No | Yes |
| Cache bypass reasoning | No | No | Yes |
| Secret-aware explain output | No | No | Yes |
Why this makes daily developer work easier
- Fewer mystery reruns:
--explainshows why a task reran. - Fewer broken local states: graph tasks promote declared outputs transactionally.
- Less tribal knowledge: contracts (
@in,@out,@env,@requires) make intent explicit. - Cleaner migration path: keep Make/Just while porting one pipeline at a time.
Migration flow (recommended)
Makefile to broskifile conversion examples
Example A: simple build + test
build:
cargo build --release
test:
cargo test
version = "0.5"
build:
@in src/**/* Cargo.toml Cargo.lock
@out target/release
cargo build --release
test: build
@in src/**/* Cargo.toml Cargo.lock tests/**/*
@out .broski/stamps/test.ok
cargo test
touch .broski/stamps/test.ok
Example B: env-sensitive command
release:
RUSTFLAGS="-D warnings" cargo build --release
release:
@in src/**/* Cargo.toml Cargo.lock
@out target/release
@env RUSTFLAGS=-D warnings
cargo build --release
Justfile to broskifile conversion examples
Example A: parameterized build
build target mode="release":
cargo build --bin {{target}} --{{mode}}
build [target] [mode="release"]:
@in src/**/* Cargo.toml Cargo.lock
@out dist/{{ target }}
cargo build --bin {{ target }} --{{ mode }}
Example B: interactive dev workflow
dev:
docker compose up
dev:
@mode interactive
docker compose up
Decision checklist: when to choose graph mode
Use graph mode when:
- task outputs are meaningful artifacts you want to reuse
- rerun cost is non-trivial (build/test/package)
- you need cache explainability for CI debugging
Use interactive mode when:
- process is long-running (dev server, watcher, REPL)
- task should stream output directly to terminal
- caching is intentionally bypassed
Command recipes teams use most
# Validate graph shape and rerun logic without execution
broski run ci --dry-run --explain
# Show dependency layers as text
broski graph ci --format text
# Render graph for visualization in PR review
broski graph ci --format dot > graph.dot
# Force a one-time rebuild, then inspect normal behavior
broski run build --force
broski run build --explain
# Task-level pass-through args
broski test -- --grep smoke