Skip to content
Dev Tools Beginner Tutorial

Replace Makefiles with Just, the Modern Command Runner

Set up a parameterized justfile so your whole team runs build, test, and deploy identically.

Lenn Voss
Lenn Voss
Cloud & Infrastructure Writer · Aug 2, 2026 · 4 min read
Replace Makefiles with Just, the Modern Command Runner

What you'll build

You'll replace a project Makefile with a justfile powered by Just, giving your team one self-documenting entry point — just build, just test, just deploy staging — with parameters, .env loading, and none of Make's tab-and-.PHONY baggage.

Prerequisites

  • macOS, Linux, or Windows. Commands below are shown for macOS/Linux with bash; Just itself works the same on Windows.
  • Verified against just 1.57.0 (July 2026). Anything ≥ 1.40 will run this tutorial unchanged; distro packages can be older, so check just --version after installing.
  • No runtime dependencies — Just is a single binary, and recipes here use only standard shell tools.

1. Install Just

Pick your platform:

# macOS
brew install just

# Ubuntu 24.04+/Debian 13+
sudo apt install just

# Windows
winget install --id Casey.Just --exact

# Any platform with Rust
cargo install just

If your distro's package is stale, grab the latest prebuilt binary instead (put ~/bin on your PATH first):

curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to ~/bin

Confirm: just --version should print just 1.57.0 (or newer).

2. Set up a demo project

Create a tiny project so every recipe below actually runs:

mkdir just-demo && cd just-demo
mkdir src
echo 'console.log("hello");' > src/app.js
printf '#!/usr/bin/env bash\ntest -f dist/app.js && echo "1 test passed"\n' > run-tests.sh
chmod +x run-tests.sh
echo 'DEPLOY_USER=ci-bot' > .env

3. Write the justfile

Create a file named justfile (no extension) in the project root:

set shell := ["bash", "-euo", "pipefail", "-c"]
set dotenv-load

# list available recipes
default:
    @just --list

# copy the app into dist/
build:
    mkdir -p dist
    cp -r src/* dist/
    @echo "build complete"

# run the test suite; extra args pass through, e.g. `just test -v`
test *args: build
    ./run-tests.sh {{args}}

# deploy to an environment (staging by default)
deploy env="staging": test
    @echo "deploying to {{env}} as ${DEPLOY_USER}"

What's going on, line by line:

  • set shell makes every recipe run under bash with strict flags, so failures stop the run instead of scrolling past — the behavior you'd bolt onto Make with SHELL and .SHELLFLAGS.
  • set dotenv-load reads .env into the environment, which is why ${DEPLOY_USER} works without exporting anything.
  • The first recipe runs when you type bare just, so pointing it at just --list turns your justfile into its own help screen. The @ prefix suppresses echoing the command itself.
  • Comments directly above a recipe become its description in just --list — documentation for free.
  • test *args: accepts zero or more arguments and splices them in with {{args}}; deploy env="staging": takes one parameter with a default. Recipes after the colon (build, test) are dependencies and run first.
  • Indent with spaces or tabs — Just accepts either, as long as each recipe is consistent.

4. Run it

just deploy prod

Just runs the dependency chain build → test → deploy, and prod overrides the default parameter. Try just test --verbose to see variadic pass-through (the flag lands in run-tests.sh's $@).

Verify it works

Bare just should print the recipe list with your comments as docs:

$ just
Available recipes:
    build                # copy the app into dist/
    default              # list available recipes
    deploy env="staging" # deploy to an environment (staging by default)
    test *args           # run the test suite; extra args pass through, e.g. `just test -v`

And a full run:

$ just deploy
mkdir -p dist
cp -r src/* dist/
build complete
./run-tests.sh
1 test passed
deploying to staging as ci-bot

If you see both, you're done — commit the justfile and .env handling conventions, and your whole team runs identical commands.

Troubleshooting

  • error: recipe line has inconsistent leading whitespace — you mixed tabs and spaces inside one recipe (usually from pasting). Unlike Make, either works, but not both; re-indent the recipe uniformly.
  • error: justfile does not contain recipe biuld`` — a typo; Just suggests the closest match ("Did you mean build?"). Run just --list to see what actually exists.
  • cp: cannot stat 'src/*' after a cd on the previous line — each recipe line runs in a fresh shell, so cd doesn't persist. Chain with cd somewhere && command on one line, or start the recipe with #!/usr/bin/env bash to run the whole body as a single script.
  • error: unknown setting on a justfile that works for teammates — your binary is older than the setting (e.g. default-list needs ≥ 1.52). Check just --version; apt versions lag, so install via the install.sh one-liner above.

Next steps

Read the Just manual for the features you'll want next: [group] and [private] attributes to organize --list output, [confirm] to guard destructive recipes like deploy prod, invoking recipes from subdirectories, and shell completion scripts for bash/zsh/fish. When the justfile grows, split it with import or per-directory modules.

Sources & further reading

  1. Just Programmer's Manual — just.systems
  2. Just Programmer's Manual - Packages — just.systems
  3. Just Programmer's Manual - Recipe Parameters — just.systems
  4. just releases (1.57.0) — github.com
  5. just CHANGELOG — github.com
Lenn Voss
Written by
Lenn Voss · Cloud & Infrastructure Writer

Lenn writes about cloud platforms, Kubernetes internals, and the infrastructure decisions that quietly make or break engineering organizations. Based in Berlin's vibrant tech scene, they have a talent for turning dense platform-engineering topics into prose that people actually finish reading.

Discussion 0

Join the discussion

Sign in or create an account to comment and vote.

No comments yet

Be the first to weigh in.

Related Reading