Code Examples

Real-world examples showing cross-platform failures and modern solutions

The Cross-Platform Problem

Common Task: Clean & Run with Environment Variable

A typical development task: delete a build directory, set an environment variable, and run an application.

Makefile (fails on Windows)

# Makefile
clean-and-run:
rm -rf build
MY_VAR=production go run ./...

Fails on Windows: rm -rf not available, MY_VAR=... syntax invalid

npm scripts (requires helper packages)

// package.json
"scripts": {
"clean-and-run": "rm -rf build && MY_VAR=production go run ./..."
}

Same problems as Makefile. Requires rimraf and cross-env:

// Fixed but with dependencies
"scripts": {
"clean-and-run": "rimraf build && cross-env MY_VAR=production go run ./..."
}

Modern Runners (works everywhere)

just
# justfile
clean-and-run:
rm -rf build
MY_VAR=production go run ./...

just handles cross-platform differences automatically

Task
# Taskfile.yml
tasks:
clean-and-run:
cmds:
- rm -rf build
env:
MY_VAR: production
cmds:
- go run ./...

Task provides built-in cross-platform command handling

Tool-Specific Examples

just Examples

Basic Recipe with Arguments

# Run tests for a specific package
test package="all":
@echo "Testing {{package}}"
{{if package == "all" { "go test ./..." } else { "go test ./{{package}}" }}}

Usage: just test or just test auth

Environment Variables and Shebang

# Complex deployment script
deploy env:
#!/usr/bin/env python3
import os
import subprocess
env = "{{env}}"
if env not in ["dev", "staging", "prod"]:
raise ValueError("Invalid environment")
subprocess.run(f"docker build -t app:{env} .", shell=True)

Recipe Dependencies

# Build depends on clean and test
build: clean test
go build -o bin/app ./cmd/app
clean:
rm -rf bin/
test:
go test ./...

Task Examples

Checksum-based Caching

# Taskfile.yml - Only rebuilds when source changes
tasks:
build-frontend:
sources:
- "src/**/*.ts"
- "src/**/*.tsx"
- "package.json"
generates:
- "dist/**/*"
cmds:
- npm run build

Parallel Dependencies

# Dependencies run in parallel by default
tasks:
deploy:
deps: [build-frontend, build-backend, run-tests]
cmds:
- docker build -t app .
- docker push app:latest

Variables and Templates

# Using Go template syntax
vars:
APP_NAME: myapp
VERSION:
sh: git describe --tags --always
tasks:
docker-build:
cmds:
- docker build -t {{.APP_NAME}}:{{.VERSION}} .

Mage Examples

Basic Build Target

// magefile.go
package main
import (
"fmt"
"os/exec"
)
// Build compiles the application
func Build() error {
fmt.Println("Building application...")
cmd := exec.Command("go", "build", "-o", "bin/app", "./cmd/app")
return cmd.Run()
}

Usage: mage build

Complex Logic with Error Handling

// Advanced deployment with rollback capability
func Deploy(env string) error {
if env != "staging" && env != "prod" {
return fmt.Errorf("invalid environment: %s", env)
}
if err := runTests(); err != nil {
return fmt.Errorf("tests failed: %w", err)
}
version := getCurrentVersion()
if err := deployToEnvironment(env, version); err != nil {
fmt.Printf("Deploy failed, rolling back to previous version\\n")
return rollback(env)
}
return nil
}

doit Examples

Data Processing Pipeline

# dodo.py - ML data pipeline
import pandas as pd
from pathlib import Path
def task_download_data():
"""Download raw data from API"""
return {
'actions': ['python scripts/download.py'],
'targets': ['data/raw.csv'],
'uptodate': [False] # Always download fresh data
}
def task_clean_data():
"""Clean and preprocess data"""
return {
'file_dep': ['data/raw.csv'],
'targets': ['data/cleaned.csv'],
'actions': ['python scripts/clean.py']
}

Dynamic Task Generation

# Generate tasks for multiple models
MODELS = ['linear', 'random_forest', 'neural_net']
def task_train_model():
"""Train multiple models in parallel"""
for model in MODELS:
yield {
'name': model,
'file_dep': ['data/cleaned.csv'],
'targets': [f'models/{model}.pkl'],
'actions': [f'python train.py --model {model}']
}

Usage: doit train_model (runs all models in parallel)

Performance Comparison

Startup Time Test

Running time tool --help to measure startup overhead:

Fast (Compiled)

just --help ~3ms
task --help ~5ms
make --help ~8ms

Slow (Interpreted/Runtime)

npm run --help ~400ms
doit help ~25ms
mage -h ~15ms

Impact: For commands run hundreds of times per day during development, the 400ms npm scripts overhead becomes noticeable and disruptive to workflow.