The best of Make and Just, combined. File dependencies, clean syntax, parallel execution, and watch mode.
$ curl -fsSL jakefile.dev/install.sh | sh # Variables
app_name = "myapp"
# Load environment
@dotenv
# Default task
@default
task build:
@description "Build the application"
cargo build --release
# File target - only rebuilds when changed
file dist/app: src/**/*.rs
cargo build --release
cp target/release/{{app_name}} dist/app
# Conditional logic
task deploy: [build, test]
@confirm "Deploy to production?"
@if env(CI)
./scripts/deploy-ci.sh
@else
./scripts/deploy-local.sh
@end See how Jake compares to Make and Just for a common build task.
CC = gcc
CFLAGS = -Wall
.PHONY: all clean test
all: build test
build: main.o utils.o
$(CC) -o app main.o utils.o
%.o: %.c
$(CC) $(CFLAGS) -c $<
test: build
./run_tests.sh
clean:
rm -f *.o app cc := "gcc"
cflags := "-Wall"
default: all
all: build test
build:
{{cc}} {{cflags}} -c main.c
{{cc}} {{cflags}} -c utils.c
{{cc}} -o app main.o utils.o
test: build
./run_tests.sh
clean:
rm -f *.o app cc = "gcc"
cflags = "-Wall"
@default
task all: [build, test]
# Only rebuilds when sources change!
file app: *.c
{{cc}} {{cflags}} -o app *.c
task test: [app]
./run_tests.sh
task clean:
rm -f *.o app | Feature | Make | Just | Jake |
|---|---|---|---|
| File-based dependencies | ✓ | ✗ | ✓ |
| Clean, readable syntax | ✗ | ✓ | ✓ |
| Parallel execution | ✓ | ~ | ✓ |
| Glob patterns in deps | ~ | ✗ | ✓ |
| Watch mode | ✗ | ✗ | ✓ |
| Pre/post hooks | ✗ | ✗ | ✓ |
Jake combines the best features from Make and Just, plus unique capabilities you won't find anywhere else.
Like Make, track file modifications and only rebuild what changed. Glob patterns included.
No cryptic symbols or tab sensitivity. Just readable, maintainable build scripts.
Run independent tasks simultaneously. Automatic job scheduling with -j flag.
Built-in file watching. Re-run tasks automatically when sources change.
Split large Jakefiles into modules. Namespaced imports prevent collisions.
if/elif/else logic in your tasks. Check env vars, file existence, and more.
Run setup and cleanup commands automatically. Global or per-task hooks.
Load environment variables from .env files. Multiple files supported.
File targets track modification times and only rebuild what changed. Chain them together for multi-stage builds that skip unnecessary work.
src/**/*.ts # File target with glob pattern
file dist/bundle.js: src/**/*.ts
esbuild src/index.ts --bundle --outfile=dist/bundle.js
# Chain file targets together
file dist/app.min.js: dist/bundle.js
terser dist/bundle.js -o dist/app.min.js
# Tasks can depend on file targets
task build: [dist/app.min.js]
echo "Build complete!" $ jake build
→ dist/bundle.js
esbuild src/index.ts --bundle --outfile=dist/bundle.js
✓ dist/bundle.js (0.42s)
→ dist/app.min.js
terser dist/bundle.js -o dist/app.min.js
✓ dist/app.min.js (0.18s)
→ build
echo "Build complete!"
✓ build (0.01s)
$ jake build # Run again - no changes!
⊘ dist/bundle.js (up to date)
⊘ dist/app.min.js (up to date)
✓ build (0.01s) # Clear, descriptive task definitions
@group build
@desc "Build the application for production"
task build mode="release":
cargo build --{{mode}}
# Aliases for common shortcuts
task build | b | compile:
cargo build
# Private helpers (hidden from -l)
task _setup-env:
@quiet
export NODE_ENV=production $ jake buidl # Oops, typo!
error: Recipe 'buidl' not found
Did you mean: build?
$ jake -s build # Inspect recipe
Recipe: build
Type: task
Group: build
Desc: Build the application for production
Aliases: b, compile
Parameters:
mode (default: "release")
Commands:
cargo build --{{mode}} Clean syntax without tab sensitivity or cryptic symbols. Plus intelligent tooling that catches your mistakes and helps you explore.
jake -s build shows full details task build | b | compile: for shortcuts Parallel execution, live file watching, and conditional logic. Control exactly how and when your tasks run.
jake -j4 runs independent tasks simultaneously jake -w rebuilds on file changes @if/@elif/@else for dynamic behavior # Parallel task execution
task all: [frontend, backend, docs]
# Watch mode with custom patterns
task dev:
@watch src/**/*.ts tests/**/*.ts
npm run dev
# Conditional logic
task deploy:
@if env(CI)
./deploy-ci.sh
@elif eq($ENV, "prod")
@confirm "Deploy to production?"
./deploy-prod.sh
@else
./deploy-staging.sh
@end $ jake -j4 all # 4 parallel jobs
→ frontend │ → backend │ → docs
✓ docs (1.2s)
✓ frontend (2.8s)
✓ backend (3.1s)
✓ all (3.1s total)
$ jake -w dev # Watch mode
👀 Watching src/**/*.ts, tests/**/*.ts
✓ dev (0.8s)
Changed: src/index.ts
→ dev (rebuilding...)
✓ dev (0.3s) # Import with namespacing
@import "scripts/docker.jake" as docker
@import "scripts/k8s.jake" as k8s
# Environment configuration
@dotenv
@dotenv ".env.local"
@export NODE_ENV=production
# Validation before running
@needs docker kubectl helm
@require AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY
# Platform-specific tasks
@platform macos
task install-deps:
brew install protobuf $ jake docker.build k8s.deploy
→ docker.build
✓ docker.build (12.4s)
→ k8s.deploy
✓ k8s.deploy (3.2s)
$ jake deploy # Missing requirement
error: Required command not found: helm
hint: Install with: brew install helm
$ jake deploy # Missing env var
error: Required environment variable not set:
AWS_ACCESS_KEY_ID Split your Jakefile into modules, validate requirements before running, and handle different platforms gracefully.
@import "x.jake" as x @needs and @require catch issues early @platform macos linux for OS-aware tasks See Jake in action with real-world examples.
Automatically rebuild when files change
# Terminal
$ jake -w build
# Output:
Watching src/**/*.ts
✓ build (0.42s)
# Edit a file...
Changed: src/index.ts
✓ build (0.18s) Run independent tasks simultaneously
task all: [frontend, backend, docs]
@description "Build everything"
task frontend:
npm run build
task backend:
cargo build --release
task docs:
mkdocs build
# Run with 4 parallel jobs
$ jake -j4 all Split your Jakefile into reusable modules
# Jakefile
@import "scripts/docker.jake" as docker
@import "scripts/deploy.jake" as deploy
task release: [build, docker.push]
@confirm "Deploy to production?"
deploy.production
# Usage:
$ jake docker.build
$ jake deploy.staging Setup and cleanup that always runs
# Global hooks
@pre echo "Starting build..."
@post echo "Build complete!"
# Per-task hooks
task test:
@pre docker-compose up -d
npm test
@post docker-compose down
# Error handling
@on_error notify "Build failed!" Get started with Jake in seconds. No complex setup required.
$ curl -fsSL jakefile.dev/install.sh | sh