Aller au contenu

Just Cheat Sheet

Overview

Just is a command runner that lets you save and run project-specific commands in a file called justfile. Unlike Make, Just is not a build system — it focuses purely on running commands. It supports variables, arguments, conditional execution, and works across Linux, macOS, and Windows.

Just uses a syntax inspired by Make but without the quirks like tab-sensitivity for indentation or implicit rules. Recipes in a justfile are simply named sets of shell commands that can accept parameters, have dependencies, and use built-in functions for common tasks.

Installation

# macOS
brew install just

# Linux - prebuilt binary
curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin

# Cargo (any platform)
cargo install just

# Arch Linux
sudo pacman -S just

# Ubuntu/Debian (via prebuilt .deb)
wget https://github.com/casey/just/releases/latest/download/just-x86_64-unknown-linux-musl.tar.gz
tar xzf just-x86_64-unknown-linux-musl.tar.gz just
sudo mv just /usr/local/bin/

# Verify
just --version

Shell Completion

# Bash
just --completions bash > ~/.local/share/bash-completion/completions/just

# Zsh
just --completions zsh > ~/.zfunc/_just

# Fish
just --completions fish > ~/.config/fish/completions/just.fish

Core Commands

CommandDescription
justRun the default recipe
just <recipe>Run a specific recipe
just <recipe> arg1 arg2Run recipe with arguments
just --listList available recipes
just --summaryOne-line summary of recipes
just --show <recipe>Show recipe source
just --evaluateShow variable values
just --dry-run <recipe>Print commands without running
just --chooseSelect recipe interactively (needs fzf)
just --fmtFormat the justfile
just --check --fmtCheck formatting without changes

Justfile Syntax

Basic Recipes

# justfile

# Default recipe (first one listed)
default:
    echo "Hello from just!"

# Simple build recipe
build:
    cargo build --release

# Recipe with multiple commands
deploy: build
    scp target/release/myapp server:/opt/app/
    ssh server "systemctl restart myapp"

# Recipe with arguments
greet name:
    echo "Hello, {{name}}!"

# Default argument values
serve port='8080':
    python3 -m http.server {{port}}

Variables and Settings

# Variables
version := "1.0.0"
build_dir := "target/release"
image := "myapp:" + version

# Environment variables
export DATABASE_URL := "postgres://localhost/mydb"

# Settings
set dotenv-load         # Load .env file
set shell := ["bash", "-cu"]
set positional-arguments
set windows-shell := ["powershell.exe", "-NoLogo", "-Command"]

Dependencies and Ordering

# Recipe dependencies
build: clean compile test
    echo "Build complete"

clean:
    rm -rf build/

compile:
    gcc -o build/app src/main.c

test: compile
    ./build/app --test

# Run dependency with arguments
push version: (build version)
    git tag {{version}}
    git push --tags

build version:
    echo "Building version {{version}}"

Configuration

Conditional Execution

# OS-specific commands
install:
    #!/usr/bin/env bash
    if [[ "{{os()}}" == "macos" ]]; then
        brew install myapp
    elif [[ "{{os()}}" == "linux" ]]; then
        sudo apt install myapp
    fi

# Conditional variable
db := if env_var_or_default("CI", "") == "true" { "postgres" } else { "sqlite" }

# Error handling
check:
    test -f config.yaml || (echo "Missing config!" && exit 1)

Built-in Functions

# System info
info:
    echo "OS: {{os()}}"
    echo "Arch: {{arch()}}"
    echo "Home: {{env_var('HOME')}}"
    echo "Invocation dir: {{invocation_directory()}}"
    echo "Just executable: {{just_executable()}}"

# String functions
process name:
    echo "Upper: {{uppercase(name)}}"
    echo "Lower: {{lowercase(name)}}"
    echo "Replaced: {{replace(name, '-', '_')}}"

# Path functions
paths:
    echo "Parent: {{parent_directory(justfile())}}"
    echo "Stem: {{file_stem('archive.tar.gz')}}"
    echo "Extension: {{extension('photo.jpg')}}"

Shebang Recipes

# Python recipe
analyze:
    #!/usr/bin/env python3
    import json
    with open("data.json") as f:
        data = json.load(f)
    print(f"Records: {len(data)}")

# Node recipe
transform:
    #!/usr/bin/env node
    const fs = require('fs');
    const data = fs.readFileSync('input.txt', 'utf8');
    console.log(data.toUpperCase());

Advanced Usage

Private Recipes and Documentation

# Documented recipe (shown in --list)
# Build the application for production
build:
    cargo build --release

# Private recipe (hidden from --list)
[private]
_helper:
    echo "internal helper"

# Grouped recipes with doc comments
[group('database')]
db-migrate:
    diesel migration run

[group('database')]
db-reset:
    diesel database reset

# Confirm before running
[confirm("Are you sure you want to deploy?")]
deploy:
    ./deploy.sh production

Working Directory and Imports

# Change working directory for recipe
[working-directory('frontend')]
build-frontend:
    npm run build

# Import other justfiles
import 'tasks/docker.just'
import? 'local.just'  # Optional import

# Modules
mod docker 'tasks/docker.just'
# Usage: just docker build

Variadic Arguments

# Variadic positional arguments
test *args:
    cargo test {{args}}

# One-or-more variadic
docker +services:
    docker compose up {{services}}

# Combining fixed and variadic
run command *args:
    {{command}} {{args}}

Troubleshooting

IssueSolution
error: Expected '*', '## ', '$', '(', '+', '/', '@'...Check indentation — use spaces or tabs consistently
Recipe not foundRun just --list to see available recipes
.env not loadedAdd set dotenv-load to justfile
Wrong shell on WindowsSet set windows-shell appropriately
Variables not expandingUse {{var}} syntax, not $(var) or $var
Can’t find justfileJust searches parent directories; check file name is exactly justfile
# Debug: show what would run
just --dry-run build

# Show all variables
just --evaluate

# Dump complete justfile after imports
just --dump

# Use a different justfile
just --justfile path/to/justfile build

# Override a variable
just version="2.0" build