Skip to main content

Using the just Task Runner

·14 mins

The just tool is a task runner. It provides a consistent framework for working with sets of tasks, which may be written in any scripting language and can run on multiple platforms.

How just Works #

Each copy of just is a single executable file, with versions for Linux, macOS and Windows. This executable is relatively small, about 5Mb for the 64-bit Linux version. It uses sets of tasks that are defined in plain-text files. You may write a task in any programming language that runs with an interpreter, such as UNIX shells, PowerShell, Python, JavaScript or Nu shell.

This means that you can add just to any environment and use whichever scripting languages are available. If you define multiple implementations of a task, just runs the correct implementation for the current platform. It also provides other features for you to customise the behavior of tasks for different environments.

For example, you may use built-in functions for just in your tasks. These functions include identifying the host environment, reading environment variables, generating UUIDs, calculating file checksums and formatting string inputs. These enable you to get consistent inputs for your tasks across different platforms, even if the scripting language that you use does not have these features.

Terms: In just, tasks are referred to as recipes. The text files that contain recipes are known as justfiles.

You do not need to set up or configure just, because it only requires a copy of the executable, and has no configuration files apart from the files that contain the recipes. Here is an example of a justfile:

# Recipes for Hugo
#
# https://gohugo.io/

# Build Website
build:
    @hugo

# Remove generated files
clean:
    #!/usr/bin/env sh
    set -eu
    HUGO_TEMP_PATHS=".hugo_build.lock public"
    echo "Removing temporary files for Hugo..."
    for HUGO_TEMP_PATH in $HUGO_TEMP_PATHS
    do
      rm -fr $HUGO_TEMP_PATH
      echo "Removed $HUGO_TEMP_PATH"
    done

# Deploy Website
deploy: build
    @hugo deploy

# Run Website in development server
serve:
    @hugo server

The Backwards Compatibility Guarantee #

The behaviour of just is covered by a backwards compatibility guarantee. To verify that new versions of just do not break compatibility, the just project maintain automation to test against justfiles that are published as Open Source.

This guarantee makes just more suitable for public Open Source projects than other alternatives. The developers of the project simply need to specify the minimum version of just that supports the features that they use. Tasks will work for contributors and users that have any version of just that is the same or more recent than this minimum version.

Installing just #

If possible, use a tool that enables you to specify which versions of just to install. This means that you can install the most recent version of just that is available. You can use the packages for your programming language, a tool version manager like mise, or the feature for Dev Containers.

If you do not wish to use a tool, see the section on how to install just with a script.

These methods also enable you to add a copy of just to a specific project, or install just into a user account so that it is available for all of your work. If you install a copy of just into a user account you can integrate it with your shell.

If possible, use the Python or Rust tools to install just. The Python and Rust packages contain a copy of the just executable. Other tools may download files from GitHub.

You can also install just with operating system packages. These packages may provide older versions of just.

Installing just for a User with Python Tools #

If you use Python, you can install just into your user account with your existing tools. It is available on the Python Package Index as rust-just.

To install just with uv, run this command:

uv tool install rust-just==1.36.0

To install just with pipx, run this command:

pipx install rust-just==1.36.0

Adding a Copy of just to a Project #

Python, Rust and Node.js projects may use packages for just:

  • Node.js: Use the just-install npm package
  • Python: Use the rust-just package
  • Rust: To include just in a Rust project, add just as a package in Cargo.

If necessary, you can use the installation script to download a copy of just into a directory within the project. If you do this, remember to exclude the path of the just executable file from version control.

Installing just with mise #

This command installs the latest version of just with mise and makes it available to your user account:

mise use -gy just

You can also use mise to specify alternate versions of just for specific projects in the same ways that it manages other tools.

Adding just to a Dev Container #

If you are using a Visual Studio Code Dev Container, you can add the feature guiyomh/features/just to your devcontainer.json file to download just from GitHub:

    "features": {
        "ghcr.io/guiyomh/features/just:0": {
            "version": "1.36.0"
        }
    }

Installing just with a Script #

The just project provide a script for downloading just from GitHub. You may either fetch this installation script each time, as the documentation describes, or save it. To ensure that container image builds are consistent, use a saved copy of the script when you build Docker container images.

To save the installation script:

curl -L https://just.systems/install.sh > scripts/install-just.sh

To use the installation script, call it with –tag and –to The –tag specifies the version of just. The –to specifies which directory to install it to:

./scripts/install-just.sh --tag 1.36.0 --to $HOME/.local/bin

Installing just with Operating System Packages #

You can install just with an operating system package manager, if necessary. For example, these commands install just:

winget install --id Casey.Just --exact  # winget on Microsoft Windows
brew install just                       # Homebrew on macOS
doas apk add just                       # apk on Alpine Linux
sudo dnf install just                   # dnf on Fedora Linux
sudo apt install just                   # apt on Ubuntu

To install just, you also need to enable the community package repository for Alpine Linux, and universe on Ubuntu 24.04 LTS or later.

Debian only includes just in the testing distribution.

See the package list page for a list of the available operating system packages.

Integrating just with Your Shell #

If you install a copy of just into a user account you can integrate with your shell to enable autocompletion and a global set of of tasks.

Enabling Shell Autocompletion #

To enable autocompletion in a shell, use –completions to generate a completion script that you install into the correct location. For example, to enable autocompletion for the Bash shell, run this command:

sudo su -c 'just --completions bash > /etc/bash_completion.d/just.bash'

To install autocompletion for the fish shell, use this command:

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

Current versions of just provide autocompletion for Bash, zsh, fish, PowerShell, elvish and Nu.

macOS and Homebrew: If you install just on macOS with Homebrew, follow these instructions for autocompletion with zsh.

Creating a User justfile for Global Tasks #

If you install just into a user account, you can define a set of recipes that are available at any time. Create a file with the name .user.justfile in your home directory to store these recipes.

Add the first recipe in the root justfile with the name help. Write @just –list in the body of the recipe. When just is invoked without the name of a recipe, it runs the first recipe in the justfile.

Here is an example of a user justfile:

# List available recipes
help:
    @just --list -f "{{ home_directory() }}/.user.justfile"

# Display system information
system-info:
    @echo "CPU architecture: {{ arch() }}"
    @echo "Operating system type: {{ os_family() }}"
    @echo "Operating system: {{ os() }}"
    @echo "Home directory: {{ home_directory() }}"

This justfile requires extra options to run. For convenience, add an alias to your shell configuration. For example, add these lines in .config/fish/config.fish to enable an alias in the Fish shell:

# Add abbr to call recipes in user Justfile by typing ".j RECIPE-NAME"
if command -s just > /dev/null
    abbr --add .j just --justfile $HOME/.user.justfile --working-directory .
end

This means that you run a task in the justfile by entering .j followed by the name of the recipe:

.j system-info

To list the recipes in your user justfile, type .j and press the Enter key.

.j

Integrating just with Other Tools #

Enabling Visual Studio Code Integration #

The nefrob.vscode-just-syntax extension provides support for justfiles in Visual Studio Code. This extension currently only provides syntax highlighting.

Enabling Integration with JetBrains IDEs #

To enable support for just in JetBrains IDEs such as PyCharm, install the Just plugin.

Using just in a Project #

Use just –init to create a justfile in the root directory of your project. You should always name the just file in the root directory of the project justfile.

If a project only requires one small set of recipes, then use a single justfile.

If you need to manage several sets of recipes, use multiple files.

Registering justfiles for EditorConfig #

To ensure that EditorConfig correctly manages the format of files for just, add this to the .editorconfig file in your project:

[{justfile, *.just}]
indent_style = space
indent_size = 4

Multiple justfiles in a Project #

You have two ways to organize the other justfiles in a project:

  1. Directory structure
  2. Modules

You can combine these approaches, but few projects will be complex enough to need to do this.

The project directory structure approach is to create a justfile in the root directory of the project, and then create an extra justfile in each sub-directory that relates to a separate area of work. You then enable fallback in the justfiles in subdirectories. Users change working directories to get different recipes from the nearest justfile, and if they specify a recipe that is not defined in the nearest justfile, then just will try justfiles in parent directories.

The next section explains how to use multiple justfiles in a directory structure.

If you are starting a new project and can require a current version of just, consider using just modules. Real-world projects often have multiple components with many tasks, and just modules enable you to define clear namespaces for recipes. Modules also provide more flexibility for organizing the files that contain your recipes.

Use just 1.31.0 or later with modules: The modules feature became available by default with just 1.31.0.

A later section in this article explains how to use modules.

Writing justfiles #

Formatting justfiles #

Follow these guidelines when writing justfiles and mod.just modules:

  • Use 4 spaces for indentation. The built-in formatting command sets indentation as 4 spaces.
  • Always put a comment in the line above each recipe. These comments appear next to the recipe in just –list.
  • Use –fmt to format your justfiles. To use this option, run this command in the same directory as the justfile that you want to format:
just --unstable --fmt

–fmt is Currently Unstable: The –fmt subcommand is unstable, which means that it is expected to work correctly, but it is not subject to the standard compatibility guarantees of just.

Writing Recipes #

Follow these guidelines when writing recipes:

  • Use parameters to get inputs for a recipe from the command-line.
  • Use dotenv files to get configuration from files.
  • Remember to use POSIX shell (sh) syntax for single-line recipes. By default, just uses the sh shell on the system.
  • When it is possible, use the built-in functions instead of shell commands, because these will behave consistently across different environments.
  • Use shebang recipes for multi-line shell recipes, as well as recipes in other languages.
  • If you need the features of a specific UNIX shell, use a shebang recipe. Set error handling for recipes that use bash.
  • Use quotes around arguments to ensure that just can identify mistakes.

More Examples of justfiles #

The GitHub project for just includes example justfiles.

Running just Recipes #

To run a recipe in a justfile, enter just followed by the name of the recipe:

just example-recipe

If a recipe accepts parameters, add the value for the parameter to the command:

just example-recipe my-parameter-value

You may always override a variable by specifying a value with the just command:

just example-recipe my-var=my-var-value

Checking justfiles #

To validate a justfile, run –fmt with –check. This returns an exit code of 0 if the justfile is formatted correctly. If the justfile is not correctly formatted, it returns an exit code of 1 and prints a diff.

just --unstable --fmt --check

–fmt is Currently Unstable: The –fmt subcommand is unstable, which means that it is expected to work correctly, but it is not subject to the standard compatibility guarantees of just.

You may also use these two options to check the behavior of just:

  • -n, –dry-run - Prints what just would do without doing it
  • –evaluate - Evaluates and prints all of the variables. If a variable name is given as an argument, it only prints the value of that variable.

Multiple justfiles in a Directory Structure #

If you use multiple justfiles in a project, consider following these guidelines:

  • Create the first recipe in the root justfile with the name help. Write @just –list in the body of the recipe. When just is invoked without the name of a recipe, it runs the first recipe in the justfile.
  • Create an extra justfile in each subdirectory that should be a separate scope of operations. For example, if you have a monorepo, create a child justfile in the main directory for each component.
  • Set fallback to true in each justfile that is NOT in the root directory of the project. This enables just to find recipes from the root justfile as well as the justfile in the current working directory.
  • If you have many recipes for a single justfile, consider putting the recipes into several .just files and using imports to combine them.
  • To ensure that you do not accidentally run a recipe from a user justfile, do NOT set fallback to true in a justfile in the root directory of a project.
  • To create namespaces for recipes, decide a standard prefix for each group of recipes, and set the name of each recipe to start with that prefix, e.g. sys-.
  • Use the no-cd attribute to define recipes that may be executed in one of several different possible directories. By default just sets the working directory to be the location of the justfile that contains the recipe.

Using Modules #

If you decide to use just modules in your project, consider following these guidelines:

  • Create the first recipe in the root justfile with the name help. Write @just –list in the body of the recipe. When just is invoked without a module or recipe name, it runs the first recipe in the justfile.
  • Create an extra mod.just file in each subdirectory that relates to a specific component or type of work. You may not need a separate module for every main subdirectory in the project.
  • Create an extra .just file in the root directory for each tool that applies to the entire project, such as pre-commit.
  • Use the root justfile to define standard tasks for the project. Each of these should call the relevant recipes in one or more modules. Avoid writing recipes in the justfile that do anything other than running recipes that are defined in modules.
  • Remember that the first recipe in each mod.just file is the default for the module. This means that the first recipe runs when a user types the module without specifying the name of the task.
  • Specify the no-cd attribute on each recipe in a module, so that the working directory of the recipe is the root directory of the project.

Example justfile for a Project with Modules #

mod precommit  # Defined by pre-commit.just file in root directory
mod python  # Defined by mod.just file in python/ directory

# List available recipes
help:
    @just --list

# Install tools and dependencies, then set up environment for development
bootstrap:
    @just install
    @just setup

# Build artifacts
build:
    @just python::build

# Install project tools and dependencies
install:
    @just python::install

# Run all checks
lint:
    @just pre-commit::check

# Set up environment for development
setup:
    @just python::setup
    @just pre-commit::setup

Note that the first recipe in this file is help, so this command runs that recipe:

just

Example just Module for a Project #

# Check the project with pre-commit
check:
    @pre-commit run --all-files

# Run a specific pre-commit check on the project
run hook-id:
    @pre-commit run "{{ hook-id }}" --all-files

# Setup pre-commit for use
setup:
    @pre-commit install

Note that the first recipe in this file is check, so this command runs that recipe:

just pre-commit

Resources #