Just Configuration Standards
Core Philosophy
Apply these principles in strict priority order:
- Discoverability —
just --listis the entry point. Every recipe is documented, grouped, and easy to find. - Idiomaticity — Follow
justconventions. Use attributes, modules, and settings as the tool intends. - Modularity — Group related recipes into submodules. A flat file with 30 recipes is unmaintainable.
- Simplicity — Recipes are thin wrappers. Complex logic belongs in scripts, not justfiles.
Hard Rules
These are non-negotiable. NEVER violate them.
Never use hyphens to namespace recipes
If two or more recipes share a prefix, they belong in a module.
Hyphenated namespacing creates a flat, unsearchable list and
defeats just's built-in module system.
# WRONG — hyphenated namespacing
docker-build:
docker build -t app .
docker-run:
docker run app
docker-push:
docker push app
# RIGHT — use a submodule
mod docker
# docker.just
[doc('Build the container image')]
build:
docker build -t app .
[doc('Run the container')]
run:
docker run app
[doc('Push to registry')]
push:
docker push app
Invocation becomes just docker build, just docker run — clear,
grouped, and discoverable via just --list.
Always use attributes for organization
Every public recipe MUST have a [doc()] attribute. Group related
recipes with [group()]. Hide helpers with [private].
[doc('Run the full test suite')]
[group('test')]
test:
pytest
[doc('Run tests with coverage report')]
[group('test')]
coverage:
pytest --cov
[private]
ensure-venv:
[ -d .venv ] || python -m venv .venv
Always set shell for non-POSIX environments
If the project may run on Windows or needs a specific shell, declare it explicitly.
set shell := ["bash", "-euo", "pipefail", "-c"]
Use shebang recipes for multi-line logic
Each line in a normal recipe runs in a separate shell. For
multi-line logic, use a shebang recipe or the [script]
attribute.
[script]
[doc('Generate release notes from git log')]
release-notes version:
#!/usr/bin/env bash
set -euo pipefail
tag="v{{version}}"
git log --oneline "$(git describe --tags --abbrev=0)..$tag"
Module Organization
The mod keyword
Use mod to split a justfile into focused submodules. Each
module gets its own namespace in just --list.
# justfile (root)
mod docker
mod db
mod ci
File layout
Two conventions — pick one per project:
# Flat: one file per module
justfile
docker.just
db.just
ci.just
# Nested: directory per module (for complex modules)
justfile
docker/
mod.just
db/
mod.just
migrations.just # sub-submodule
For nested modules, the entry point must be mod.just inside
the directory.
Module comments
Add a doc comment above mod to describe the module in
just --list:
# Docker container management
mod docker
# Database operations
mod db
Recipe Design
Parameters and defaults
[doc('Deploy to target environment')]
deploy env="staging":
./scripts/deploy.sh {{env}}
Variadic arguments
[doc('Run specific test files')]
test *files:
pytest {{files}}
The + prefix requires at least one argument:
[doc('Install packages')]
install +packages:
pip install {{packages}}
Dependencies
[doc('Build and run')]
run: build
./target/release/app
[doc('Compile the project')]
build:
cargo build --release
Parameterized dependencies:
[doc('Push to production')]
push: (deploy "production")
@echo 'Pushed to production'
Guard patterns
Use confirmation for destructive recipes:
[confirm('This will drop the database. Continue? (y/N)')]
[doc('Drop and recreate the database')]
[group('db')]
db-reset:
dropdb myapp && createdb myapp
Settings
Place settings at the top of the justfile, before any recipes.
# Load .env file automatically
set dotenv-load
# Use bash with strict mode
set shell := ["bash", "-euo", "pipefail", "-c"]
# Suppress recipe echo by default
set quiet
# Export all variables as environment variables
set export
# Enable positional arguments ($1, $2 in shell)
set positional-arguments
Essential settings
| Setting | Purpose |
|---|---|
set dotenv-load |
Auto-load .env file |
set shell |
Explicit shell for all recipes |
set quiet |
Suppress echoing recipe lines |
set export |
Export all just variables to env |
set positional-arguments |
Pass args as $1, $2, etc. |
set fallback |
Search parent dirs for justfile |
set tempdir |
Directory for temporary files |
Attributes
| Attribute | Purpose |
|---|---|
[doc('...')] |
Description shown in just --list |
[group('...')] |
Group in just --list output |
[private] |
Hide from just --list |
[confirm('...')] |
Require confirmation before running |
[no-cd] |
Don't change to justfile directory |
[no-exit-message] |
Suppress error exit message |
[script] |
Run recipe body as single script |
[linux] |
Only run on Linux |
[macos] |
Only run on macOS |
[windows] |
Only run on Windows |
Anti-Patterns
Hyphenated namespacing
Already covered in Hard Rules. Use mod submodules instead.
Bare recipes without documentation
Every public recipe must have [doc()]. Without it, just --list
shows recipe names with no context.
# Bad
build:
cargo build
# Good
[doc('Build the project in release mode')]
build:
cargo build --release
Missing settings
A justfile without set shell is fragile across platforms.
A justfile without set dotenv-load forces users to manually
source environment files.
Line-by-line shell pitfalls
Each line runs in a separate shell by default. Variables and
cd don't carry across lines.
# BROKEN — cd has no effect on the next line
build:
cd src
make
# FIXED — single line or shebang
build:
cd src && make
# BETTER — shebang for complex logic
[script]
build:
#!/usr/bin/env bash
set -euo pipefail
cd src
make
Overloaded root justfile
If your root justfile has more than ~10 recipes, split into modules. The root justfile should be a table of contents: settings, module declarations, and a handful of top-level convenience recipes.
Self-Review Checklist
Before finalizing any justfile, verify:
- No hyphenated namespacing — modules used instead
- All public recipes have
[doc()]attributes - Related recipes are grouped with
[group()] - Helper recipes are marked
[private] -
set shellis declared if non-POSIX compatibility needed -
set dotenv-loadis used if.envfile exists - Multi-line logic uses shebang or
[script] - Destructive recipes use
[confirm()] - Root justfile has fewer than ~10 direct recipes
- Module file layout is consistent (flat or nested)
For complete settings reference, built-in functions, and
real-world examples, consult references/detailed-guide.md.