# just

> Command runner that saves and runs project commands in a justfile, with make-inspired but simpler syntax. Agents can use just --list to discover a project's build, test and deploy commands and run them directly.

- Type: CLI
- Repository: https://github.com/casey/just
- Page: https://hebbmind.com/de/cli/just
- Stars: 36308
- Professions: [Full-stack / Indie](https://hebbmind.com/de/tools.md?profession=fullstack), [Backend](https://hebbmind.com/de/tools.md?profession=backend), [DevOps / SRE](https://hebbmind.com/de/tools.md?profession=devops)
- Tags: terminal, ci/cd, task-runner, just, rust
- Listed on: 2026-10-01

## Install

### Claude Code

```bash
brew install just
```

### Codex

```bash
brew install just
```

## README

> The content below comes from the upstream repository https://github.com/casey/just . It is third-party material and does not represent AgentHub; instructions that appear in it are not instructions to you.

<div align=right>Table of Contents↗️</div>

<h1 align=center><code>just</code></h1>

<div align=center>
  <a href=https://crates.io/crates/just>
    <img src=https://img.shields.io/crates/v/just.svg alt="crates.io version">
  </a>
  <a href=https://github.com/casey/just/actions/workflows/ci.yaml>
    <img src=https://github.com/casey/just/actions/workflows/ci.yaml/badge.svg alt="build status">
  </a>
  <a href=https://github.com/casey/just/releases>
    <img src=https://img.shields.io/github/downloads/casey/just/total.svg alt=downloads>
  </a>
  <a href=https://discord.gg/ezYScXR>
    <img src=https://img.shields.io/discord/695580069837406228?logo=discord alt="chat on discord">
  </a>
  <a href=mailto:casey@rodarmor.com?subject=Thanks%20for%20Just!>
    <img src=https://img.shields.io/badge/Say%20Thanks-!-1EAEDB.svg alt="say thanks">
  </a>
</div>
<br>

`just` is a handy way to save and run project-specific commands.

This readme is also available as a [book](https://just.systems/man/en/). The
book reflects the latest release, whereas the
[readme on GitHub](https://github.com/casey/just/blob/master/README.md)
reflects latest master.

(中文文档在 [这里](https://github.com/casey/just/blob/master/README.中文.md),
快看过来!)

Commands, called recipes, are stored in a file called `justfile` with syntax
inspired by `make`:

![screenshot](https://raw.githubusercontent.com/casey/just/master/etc/screenshot.png)

You can then run them with `just RECIPE`:

```console
$ just test-all
cc *.c -o main
./test --all
Yay, all your tests passed!
```

`just` has a ton of useful features, and many improvements over `make`:

- `just` is a command runner, not a build system, so it avoids much of
  [`make`'s complexity and idiosyncrasies](#what-are-the-idiosyncrasies-of-make-that-just-avoids).
  No need for `.PHONY` recipes!

- Linux, macOS, Windows, and other reasonable unixes are supported with no
  additional dependencies. (Although if your system doesn't have an `sh`,
  you'll need to [choose a different shell](#shell).)

- Errors are specific and informative, and syntax errors are reported along
  with their source context.

- Recipes can accept [command line arguments](#recipe-parameters), including
  [flags and options](#recipe-flags-and-options).

- `just` has a rich [expression language](#expressions) and many
  built-in-functions.

- Wherever possible, errors are resolved statically. Unknown recipes and
  circular dependencies are reported before anything runs.

- `just` [loads `.env` files](#dotenv-settings), making it easy to populate
  environment variables.

- Recipes can be [listed from the command line](#listing-available-recipes).

- Command line completion scripts are
  [available for most popular shells](#shell-completion-scripts).

- Recipes can be written in
  [arbitrary languages](#shebang-recipes), like Python or Node.js.

- `just` can be invoked from any subdirectory, not just the directory that
  contains the `justfile`.

- `justfiles` can be organized into multiple files using [modules](#modules)
  and [imports](#imports).

- And [much more](https://just.systems/man/en/)!

If you need help with `just`, please feel free to open an issue or ping me on
[Discord](https://discord.gg/ezYScXR). Feature requests and bug reports are
always welcome!

Installation
------------

Just can be installed using your favorite [package manager](#packages), by
downloading [pre-built binaries](#pre-built-binaries), or building from source
with `cargo install just`.

### Prerequisites

`just` should run on any system with a reasonable `sh`, including Linux, macOS,
and the BSDs.

#### Windows

On Windows, `just` works with the `sh` provided by
[Git for Windows](https://git-scm.com),
[GitHub Desktop](https://desktop.github.com), or
[Cygwin](http://www.cygwin.com). After installation, `sh` must be available in
the `PATH` of the shell you want to invoke `just` from.

If you'd rather not install `sh`, you can use the `shell` setting to use the
shell of your choice.

Like PowerShell:

```just
# use PowerShell instead of sh:
set shell := ["powershell.exe", "-c"]

hello:
  Write-Host "Hello, world!"
```

…or `cmd.exe`:

```just
# use cmd.exe instead of sh:
set shell := ["cmd.exe", "/c"]

list:
  dir
```

You can also set the shell using command-line arguments. For example, to use
PowerShell, launch `just` with `--shell powershell.exe --shell-arg -c`.

(PowerShell is installed by default on Windows 7 SP1 and Windows Server 2008 R2
SP1 and later, and `cmd.exe` is quite fiddly, so PowerShell is recommended for
most Windows users.)

### Packages

#### Cross-platform

<table>
  <thead>
    <tr>
      <th>Package Manager</th>
      <th>Package</th>
      <th>Command</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><a href=https://github.com/alexellis/arkade>arkade</a></td>
      <td>just</td>
      <td><code>arkade get just</code></td>
    </tr>
    <tr>
      <td><a href=https://asdf-vm.com>asdf</a></td>
      <td><a href=https://github.com/olofvndrhr/asdf-just>just</a></td>
      <td>
        <code>asdf plugin add just</code><br>
        <code>asdf install just &lt;version&gt;</code>
      </td>
    </tr>
    <tr>
      <td><a href=https://www.rust-lang.org>Cargo</a></td>
      <td><a href=https://crates.io/crates/just>just</a></td>
      <td><code>cargo install just</code></td>
    </tr>
    <tr>
      <td><a href=https://github.com/cargo-bins/cargo-binstall>Cargo Binstall</a></td>
      <td><a href=https://crates.io/crates/just>just</a></td>
      <td><code>cargo binstall just</code></td>
    </tr>
    <tr>
      <td><a href=https://docs.conda.io/projects/conda/en/latest/index.html>Conda</a></td>
      <td><a href=https://anaconda.org/conda-forge/just>just</a></td>
      <td><code>conda install -c conda-forge just</code></td>
    </tr>
    <tr>
      <td><a href=https://brew.sh>Homebrew</a></td>
      <td><a href=https://formulae.brew.sh/formula/just>just</a></td>
      <td><code>brew install just</code></td>
    </tr>
    <tr>
      <td><a href=https://nixos.org/nix/>Nix</a></td>
      <td><a href=https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/ju/just/package.nix>just</a></td>
      <td><code>nix-env -iA nixpkgs.just</code></td>
    </tr>
    <tr>
      <td><a href=https://www.npmjs.com/>npm</a></td>
      <td><a href=https://www.npmjs.com/package/rust-just>rust-just</a></td>
      <td><code>npm install -g rust-just</code></td>
    </tr>
    <tr>
      <td><a href=https://pipx.pypa.io/stable/>pipx</a></td>
      <td><a href=https://pypi.org/project/rust-just/>rust-just</a></td>
      <td><code>pipx install rust-just</code></td>
    </tr>
    <tr>
      <td><a href=https://snapcraft.io>Snap</a></td>
      <td><a href=https://snapcraft.io/just>just</a></td>
      <td><code>snap install --edge --classic just</code></td>
    </tr>
    <tr>
      <td><a href=https://spack.io/>Spack</a></td>
      <td><a href=https://packages.spack.io/package.html?name=just>just</a></td>
      <td><code>spack install just</code></td>
    </tr>
    <tr>
      <td><a href=https://docs.astral.sh/uv/>uv</a></td>
      <td><a href=https://pypi.org/project/rust-just/>rust-just</a></td>
      <td><code>uv tool install rust-just</code></td>
    </tr>
  </tbody>
</table>

#### BSD

<table>
  <thead>
    <tr>
      <th>Operating System</th>
      <th>Package Manager</th>
      <th>Package</th>
      <th>Command</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><a href=https://www.freebsd.org>FreeBSD</a></td>
      <td><a href=https://www.freebsd.org/doc/handbook/pkgng-intro.html>pkg</a></td>
      <td><a href=https://www.freshports.org/deskutils/just/>just</a></td>
      <td><code>pkg install just</code></td>
    </tr>
    <tr>
      <td><a href=https://www.openbsd.org>OpenBSD</a></td>
      <td><a href=https://www.openbsd.org/faq/faq15.html>pkg_*</a></td>
      <td><a href=https://cvsweb.openbsd.org/cgi-bin/cvsweb/ports/sysutils/just>just</a></td>
      <td><code>pkg_add just</code></td>
    </tr>
  </tbody>
</table>

#### Linux

<table>
  <thead>
    <tr>
      <th>Operating System</th>
      <th>Package Manager</th>
      <th>Package</th>
      <th>Command</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><a href=https://alpinelinux.org>Alpine</a></td>
      <td><a href=https://wiki.alpinelinux.org/wiki/Alpine_Linux_package_management>apk-tools</a></td>
      <td><a href=https://pkgs.alpinelinux.org/package/edge/community/x86_64/just>just</a></td>
      <td><code>apk add just</code></td>
    </tr>
    <tr>
      <td><a href=https://www.archlinux.org>Arch</a></td>
      <td><a href=https://wiki.archlinux.org/title/Pacman>pacman</a></td>
      <td><a href=https://archlinux.org/packages/extra/x86_64/just/>just</a></td>
      <td><code>pacman -S just</code></td>
    </tr>
    <tr>
      <td>
        <a href=https://debian.org>Debian 13</a> and
        <a href=https://ubuntu.com>Ubuntu 24.04</a> derivatives</td>
      <td><a href=https://en.wikipedia.org/wiki/APT_(software)>apt</a></td>
      <td><a href=https://packages.debian.org/trixie/just>just</a></td>
      <td><code>apt install just</code></td>
    </tr>
    <tr>
      <td><a href=https://getfedora.org>Fedora</a></td>
      <td><a href=https://dnf.readthedocs.io/en/latest/>DNF</a></td>
      <td><a href=https://src.fedoraproject.org/rpms/rust-just>just</a></td>
      <td><code>dnf install just</code></td>
    </tr>
    <tr>
      <td><a href=https://www.gentoo.org>Gentoo</a></td>
      <td><a href=https://wiki.gentoo.org/wiki/Portage>Portage</a></td>
      <td><a href=https://packages.gentoo.org/packages/dev-build/just>dev-build/just</a></td>
      <td>
        <code>emerge -av dev-build/just</code>
      </td>
    </tr>
    <tr>
      <td><a href=https://nixos.org/nixos/>NixOS</a></td>
      <td><a href=https://nixos.org/nix/>Nix</a></td>
      <td><a href=https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/ju/just/package.nix>just</a></td>
      <td><code>nix-env -iA nixos.just</code></td>
    </tr>
    <tr>
      <td><a href=https://opensuse.org>openSUSE</a></td>
      <td><a href=https://en.opensuse.org/Portal:Zypper>Zypper</a></td>
      <td><a href=https://build.opensuse.org/package/show/Base:System/just>just</a></td>
      <td><code>zypper in just</code></td>
    </tr>
    <tr>
      <td><a href=https://getsol.us>Solus</a></td>
      <td><a href=https://getsol.us/articles/package-management/basics/en>eopkg</a></td>
      <td><a href=https://dev.getsol.us/source/just/>just</a></td>
      <td><code>eopkg install just</code></td>
    </tr>
    <tr>
      <td><a href=https://voidlinux.org>Void</a></td>
      <td><a href=https://wiki.voidlinux.org/XBPS>XBPS</a></td>
      <td><a href=https://github.com/void-linux/void-packages/blob/master/srcpkgs/just/template>just</a></td>
      <td><code>xbps-install -S just</code></td>
    </tr>
  </tbody>
</table>

#### Windows

<table>
  <thead>
    <tr>
      <th>Package Manager</th>
      <th>Package</th>
      <th>Command</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><a href=https://chocolatey.org>Chocolatey</a></td>
      <td><a href=https://github.com/michidk/just-choco>just</a></td>
      <td><code>choco install just</code></td>
    </tr>
    <tr>
      <td><a href=https://scoop.sh>Scoop</a></td>
      <td><a href=https://github.com/ScoopInstaller/Main/blob/master/bucket/just.json>just</a></td>
      <td><code>scoop install just</code></td>
    </tr>
    <tr>
      <td><a href=https://learn.microsoft.com/en-us/windows/package-manager/>Windows Package Manager</a></td>
      <td><a href=https://github.com/microsoft/winget-pkgs/tree/master/manifests/c/Casey/Just>Casey/Just</a></td>
      <td><code>winget install --id Casey.Just --exact</code></td>
    </tr>
  </tbody>
</table>

#### macOS

<table>
  <thead>
    <tr>
      <th>Package Manager</th>
      <th>Package</th>
      <th>Command</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><a href=https://www.macports.org>MacPorts</a></td>
      <td><a href=https://ports.macports.org/port/just/summary>just</a></td>
      <td><code>port install just</code></td>
    </tr>
  </tbody>
</table>

![just package version table](https://repology.org/badge/vertical-allrepos/just.svg)

### Pre-Built Binaries

Pre-built binaries for Linux, macOS, and Windows can be found on
[the releases page](https://github.com/casey/just/releases).

You can use the following command on Linux, macOS, or Windows to download the
latest release, just replace `DEST` with the directory where you'd like to put
`just`:

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

For example, to install `just` to `~/bin`:

```console
# create ~/bin
mkdir -p ~/bin

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

# add `~/bin` to the paths that your shell searches for executables
# this line should be added to your shell's initialization file,
# e.g. `~/.bashrc` or `~/.zshrc`
export PATH="$PATH:$HOME/bin"

# just should now be executable
just --help
```

Note that `install.sh` may fail on GitHub Actions, or in other environments
where many machines share IP addresses. `install.sh` calls GitHub APIs in order
to determine the latest version of `just` to install, and those API calls are
rate-limited on a per-IP basis. To make `install.sh` more reliable in such
circumstances, pass a specific tag to install with `--tag`.

Another way to avoid rate-limiting is to pass a GitHub authentication token to
`install.sh` as an environment variable named `GITHUB_TOKEN`, allowing it to
authenticate its requests.

[Releases](https://github.com/casey/just/releases) include a `SHA256SUM` file
which can be used to verify the integrity of pre-built binary archives.

To verify a release, download the pre-built binary archive along with the
`SHA256SUM` file and run:

```sh
shasum --algorithm 256 --ignore-missing --check SHA256SUMS
```

### GitHub Actions

`just` can be installed on GitHub Actions in a few ways.

Using package managers pre-installed on GitHub Actions runners on macOS with
`brew install just`, and on Windows with `choco install just`.

With [extractions/setup-just](https://github.com/extractions/setup-just):

```yaml
- uses: extractions/setup-just@v3
  with:
    just-version: 1.5.0  # optional semver specification, otherwise latest
```

Or with [taiki-e/install-action](https://github.com/taiki-e/install-action):

```yaml
- uses: taiki-e/install-action@just
```

### Docker

`just` is available as a Docker image from
[the GitHub Container Registry](https://ghcr.io/casey/just).

To copy `just` into a Docker image, add the following line to your
`Dockerfile`:

```dockerfile
COPY --from=ghcr.io/casey/just:latest /just /usr/local/bin/
```

After copying, `just` may also be used as part of a docker build:

```dockerfile
RUN just
```

### Release RSS Feed

An [RSS feed](https://en.wikipedia.org/wiki/RSS) of `just` releases is
available [here](https://github.com/casey/just/releases.atom).

### Node.js Installation

[just-install](https://npmjs.com/package/just-install) can be used to automate
installation of `just` in Node.js applications.

`just` is a great, more robust alternative to npm scripts. If you want to
include `just` in the dependencies of a Node.js application, `just-install`
will install a local, platform-specific binary as part of the `npm install`
command. This removes the need for every developer to install `just`
independently using one of the processes mentioned above. After installation,
the `just` command will work in npm scripts or with npx. It's great for teams
who want to make the setup process for their project as easy as possible.

For more information, see the
[just-install README file](https://github.com/brombal/just-install#readme).

### Nix Flake

The `just` repository includes a
[`flake.nix`](https://github.com/casey/just/tree/master/flake.nix) that defines
a [nix flake](https://nix.dev/concepts/flakes.html), allowing you to use `just`
as an input to another flake:

```nix
{
  inputs = {
    just.url = "github:casey/just";
  }

  outputs = {self, nixpkgs, just}: {
  }
}
```

Backwards Compatibility
-----------------------

With the release of version 1.0, `just` features a strong commitment to
backwards compatibility and stability.

Future releases will not introduce backwards incompatible changes that make
existing `justfile`s stop working, or break working invocations of the
command-line interface.

This does not, however, preclude fixing outright bugs, even if doing so might
break `justfiles` that rely on their behavior.

There will never be a `just` 2.0. Any desirable backwards-incompatible changes
will be opt-in on a per-`justfile` basis, so users may migrate at their
leisure.

Features that aren't yet ready for stabilization are marked as unstable and may
be changed or removed at any time. Using unstable features produces an error by
default, which can be suppressed by passing the `--unstable` flag,
`set unstable`, or setting the environment variable `JUST_UNSTABLE` to any
value other than `false`, `0`, or the empty string.

### Requiring a Minimum Just Version

If you use features of `just` which require a particular version, you may use
the `minimum-version`<sup>1.55.0</sup> setting to make it an error to use older
versions of `just`:

```justfile
set minimum-version := '1.55.0'
```

If `just` encounters a minimum version greater than its own version, it will
print an error message with the required version, which is hopefully better
than the confused error message it would have otherwise produced.

The `minimum-version` setting should be placed at the top of the `justfile`,
before any usage of the new feature that it guards.

Any features which change the lexer in forward-incompatible ways will still
produce an unhelpful error message, as the minimum version check is implemented
in the parser, which runs after the lexer.

Editor Support
--------------

`justfile` syntax is close enough to `make` that you may want to tell your
editor to use `make` syntax highlighting for `just`.

### Vim and Neovim

Vim version 9.1.1042 or better and Neovim version 0.11 or better support
Justfile syntax highlighting out of the box, thanks to
[pbnj](https://github.com/pbnj).

#### `vim-just`

The [vim-just](https://github.com/NoahTheDuke/vim-just) plugin provides syntax
highlighting for `justfile`s.

Install it with your favorite package manager, like
[Plug](https://github.com/junegunn/vim-plug):

```vim
call plug#begin()

Plug 'NoahTheDuke/vim-just'

call plug#end()
```

Or with Vim's built-in package support:

```console
mkdir -p ~/.vim/pack/vendor/start
cd ~/.vim/pack/vendor/start
git clone https://github.com/NoahTheDuke/vim-just.git
```

#### `tree-sitter-just`

[tree-sitter-just](https://github.com/IndianBoy42/tree-sitter-just) is an
[Nvim Treesitter](https://github.com/nvim-treesitter/nvim-treesitter) plugin
for Neovim.

### Emacs

[just-mode](https://github.com/leon-barrett/just-mode.el) provides syntax
highlighting and automatic indentation of `justfile`s. It is available on
[MELPA](https://melpa.org/) as [just-mode](https://melpa.org/#/just-mode).

[justl](https://github.com/psibi/justl.el) provides commands for executing and
listing recipes.

You can add the following to an individual `justfile` to enable `make` mode on
a per-file basis:

```text
# Local Variables:
# mode: makefile
# End:
```

### Visual Studio Code

An extension for VS Code is [available here](https://github.com/nefrob/vscode-just).

Unmaintained VS Code extensions include
[skellock/vscode-just](https://github.com/skellock/vscode-just) and
[sclu1034/vscode-just](https://github.com/sclu1034/vscode-just).

### JetBrains IDEs

A plugin for JetBrains IDEs by [linux_china](https://github.com/linux-china) is
[available here](https://plugins.jetbrains.com/plugin/18658-just).

### Kakoune

Kakoune supports `justfile` syntax highlighting out of the box, thanks to
TeddyDD.

### Helix

[Helix](https://helix-editor.com/) supports `justfile` syntax highlighting
out-of-the-box since version 23.05.

### Sublime Text

The [Just package](https://github.com/nk9/just_sublime) by
[nk9](https://github.com/nk9) with `just` syntax and some other tools is
available on [PackageControl](https://packagecontrol.io/packages/Just).

### Micro

[Micro](https://micro-editor.github.io/) supports Justfile syntax highlighting
out of the box, thanks to [tomodachi94](https://github.com/tomodachi94).

### Zed

The [zed-just](https://github.com/jackTabsCode/zed-just/) extension by
[jackTabsCode](https://github.com/jackTabsCode) is available on the
[Zed extensions page](https://zed.dev/extensions?query=just).

### Other Editors

Feel free to send me the commands necessary to get syntax highlighting working
in your editor of choice so that I may include them here.

### Language Server Protocol

[just-lsp](https://github.com/terror/just-lsp) provides a [language server
protocol](https://en.wikipedia.org/wiki/Language_Server_Protocol)
implementation, enabling features such as go-to-definition, inline diagnostics,
and code completion.

### Model Context Protocol

[just-mcp](https://github.com/promptexecution/just-mcp) provides a
[model context protocol](https://en.wikipedia.org/wiki/Model_Context_Protocol)
adapter to allow LLMs to query the contents of `justfiles` and run recipes.

Quick Start
-----------

See the installation section for how to install `just` on your computer. Try
running `just --version` to make sure that it's installed correctly.

For an overview of the syntax, check out
[this cheatsheet](https://cheatography.com/linux-china/cheat-sheets/justfile/).

Once `just` is installed and working, create a file named `justfile` in the
root of your project with the following contents:

```just
recipe-name:
  echo 'This is a recipe!'

# this is a comment
another-recipe:
  @echo 'This is another recipe.'
```

When you invoke `just`, it looks for a file named `justfile` in the current
directory and upwards, so you can invoke it from any subdirectory of your
project.

The search for a `justfile` is case insensitive, so any case, like `Justfile`,
`JUSTFILE`, or `JuStFiLe`, will work. `just` will also look for files with the
name `.justfile`, in case you'd like to hide a `justfile`.

By default, running `just` with no arguments runs the first recipe in the
`justfile`:

```console
$ just
echo 'This is a recipe!'
This is a recipe!
```

One or more arguments specify the recipe(s) to run:

```console
$ just another-recipe
This is another recipe.
```

`just` prints each command to standard error before running it, which is why
`echo 'This is a recipe!'` was printed. This is suppressed for lines starting
with `@`, which is why `echo 'This is another recipe.'` was not printed.

Recipes stop running if a command fails. Here `cargo publish` will only run if
`cargo test` succeeds:

```just
publish:
  cargo test
  # tests passed, time to publish!
  cargo publish
```

Recipes can depend on other recipes. Here the `test` recipe depends on the
`build` recipe, so `build` will run before `test`:

```just
build:
  cc main.c foo.c bar.c -o main

test: build
  ./test

sloc:
  @echo "`wc -l *.c` lines of code"
```

```console
$ just test
cc main.c foo.c bar.c -o main
./test
testing… all tests passed!
```

Recipes without dependencies will run in the order they're given on the command
line:

```console
$ just build sloc
cc main.c foo.c bar.c -o main
1337 lines of code
```

Dependencies will always run first, even if they are passed after a recipe that
depends on them:

```console
$ just test build
cc main.c foo.c bar.c -o main
./test
testing… all tests passed!
```

Recipes may depend on recipes in submodules:

```justfile
mod foo

baz: foo::bar
```

Examples
--------

A variety of `justfile`s can be found in the
[examples directory](https://github.com/casey/just/tree/master/examples) and on
[GitHub](https://github.com/search?q=path%3A**%2Fjustfile&type=code).

Recipes
-------

### The Default Recipe

When `just` is invoked without a recipe, it runs the recipe with the
`[default]` attribute, or the first recipe in the `justfile` if no recipe has
the `[default]` attribute.

This recipe might be the most frequently run command in the project, like
running the tests:

```just
test:
  cargo test
```

You can also use dependencies to run multiple recipes by default:

```just
default: lint build test

build:
  echo Building…

test:
  echo Testing…

lint:
  echo Linting…
```

If no recipe makes sense as the default recipe, you can use
`default-list`<sup>1.52.0</sup> to list the available recipes instead:

```just
set default-list := true
```

### Recipe Parameters

Recipes may have parameters. Here recipe `build` has a parameter called
`target`:

```just
build target:
  @echo 'Building {{target}}…'
  cd {{target}} && make
```

To pass arguments on the command line, put them after the recipe name:

```console
$ just build my-awesome-project
Building my-awesome-project…
cd my-awesome-project && make
```

To pass arguments to a dependency, put the dependency in parentheses along with
the arguments:

```just
default: (build "main")

build target:
  @echo 'Building {{target}}…'
  cd {{target}} && make
```

Variables can also be passed as arguments to dependencies:

```just
target := "main"

_build version:
  @echo 'Building {{version}}…'
  cd {{version}} && make

build: (_build target)
```

A command's arguments can be passed to a dependency by putting the dependency in
parentheses along with the arguments:

```just
build target:
  @echo "Building {{target}}…"

push target: (build target)
  @echo 'Pushing {{target}}…'
```

Parameters may have default values:

```just
default := 'all'

test target tests=default:
  @echo 'Testing {{target}}:{{tests}}…'
  ./test --tests {{tests}} {{target}}
```

Parameters with default values may be omitted:

```console
$ just test server
Testing server:all…
./test --tests all server
```

Or supplied:

```console
$ just test server unit
Testing server:unit…
./test --tests unit server
```

Default values may be arbitrary expressions, but expressions containing the
`+`, `&&`, `||`, or `/` operators must be parenthesized:

```just
arch := "wasm"

test triple=(arch + "-unknown-unknown") input=(arch / "input.dat"):
  ./test {{triple}}
```

The last parameter of a recipe may be variadic, indicated with either a `+` or
a `*` before the argument name:

```just
backup +FILES:
  scp {{FILES}} me@server.com:
```

Variadic parameters prefixed with `+` accept _one or more_ arguments and expand
to a string containing those arguments separated by spaces:

```console
$ just backup FAQ.md GRAMMAR.md
scp FAQ.md GRAMMAR.md me@server.com:
FAQ.md                  100% 1831     1.8KB/s   00:00
GRAMMAR.md              100% 1666     1.6KB/s   00:00
```

Variadic parameters prefixed with `*` accept _zero or more_ arguments and
expand to a string containing those arguments separated by spaces, or an empty
string if no arguments are present:

```just
commit MESSAGE *FLAGS:
  git commit {{FLAGS}} -m "{{MESSAGE}}"
```

Variadic parameters can be assigned default values. These are overridden by
arguments passed on the command line:

```just
test +FLAGS='-q':
  cargo test {{FLAGS}}
```

The number of arguments a variadic parameter accepts may be limited with the
`[arg(ARG, min=MIN)]` and `[arg(ARG, max=MAX)]` attributes<sup>1.56.0</sup>,
which require lists to be enabled:

```just
set unstable
set lists

[arg('FILES', min='2', max='4')]
backup +FILES:
  scp {{FILES}} me@server.com:
```

`min` and `max` also apply to default values.

`{{…}}` substitutions may need to be quoted if they contain spaces. For
example, if you have the following recipe:

```just
search QUERY:
  lynx https://www.google.com/?q={{QUERY}}
```

And you type:

```console
$ just search "cat toupee"
```

`just` will run the command `lynx https://www.google.com/?q=cat toupee`, which
will get parsed by `sh` as `lynx`, `https://www.google.com/?q=cat`, and
`toupee`, and not the intended `lynx` and `https://www.google.com/?q=cat toupee`.

You can fix this by adding quotes:

```just
search QUERY:
  lynx 'https://www.google.com/?q={{QUERY}}'
```

Parameters prefixed with a `$` will be exported as environment variables:

```just
foo $bar:
  echo $bar
```

Parameters may be constrained to match regular expression patterns using the
`[arg("name", pattern=PATTERN)]` attribute<sup>1.45.0</sup>:

```just
[arg('n', pattern='\d+')]
double n:
  echo $(({{n}} * 2))
```

The value of `pattern` may be a const expression<sup>1.55.0</sup>.

A leading `^` and trailing `$` are added to the pattern, so it must match the
entire argument value.

You may constrain the pattern to a number of alternatives using the `|`
operator:

```just
[arg('flag', pattern='--help|--version')]
info flag:
  just {{flag}}
```

Regular expressions are provided by the
[Rust `regex` crate](https://docs.rs/regex/latest/regex/). See the
[syntax documentation](https://docs.rs/regex/latest/regex/#syntax) for usage
examples.

Usage information for a recipe may be printed with the `--usage`
subcommand<sup>1.46.0</sup>:

```console
$ just --usage foo
Usage: just foo [OPTIONS] bar

Arguments:
  bar
```

Help strings may be added to arguments using the `[arg(ARG, help=HELP)]` attribute:

```just
[arg("bar", help="hello")]
foo bar:
```

The value `help` may be a const expression<sup>1.55.0</sup>.

```console
$ just --usage foo
Usage: just foo bar

Arguments:
  bar hello
```

#### Recipe Flags and Options

Recipe parameters are positional by default.

In this `justfile`:

```just
@foo bar:
  echo bar={{bar}}
```

The parameter `bar` is positional:

```console
$ just foo hello
bar=hello
```

The `[arg(ARG, long=OPTION)]`<sup>1.46.0</sup> attribute can be used to make a
parameter a long option.

In this `justfile`:

```just
[arg("bar", long="bar")]
foo bar:
```

The parameter `bar` is given with the `--bar` option:

```console
$ just foo --bar hello
bar=hello
```

Options may also be passed with `--name=value` syntax:

```console
$ just foo --bar=hello
bar=hello
```

The value of `long` may be omitted, in which case the option defaults to the
name of the parameter. With the following justfile, `bar` may be passed with
`--bar`:

```just
[arg("bar", long)]
foo bar:
```

The `[arg(ARG, short=OPTION)]`<sup>1.46.0</sup> attribute can be used to make a
parameter a short option.

In this `justfile`:

```just
[arg("bar", short="b")]
foo bar:
```

The parameter `bar` is given with the `-b` option:

```console
$ just foo -b hello
bar=hello
```

The value of `short` may be omitted, in which case the option defaults to the
first character of the name of the parameter. With the following justfile,
`bar` may be passed with `-b`:

```just
[arg("bar", short)]
foo bar:
```

If a parameter has both a long and short option, it may be passed using either.

Multiple short options may be combined<sup>1.55.0</sup>, for example `-abc` is
equivalent to `-a -b -c`. A short option which takes a value may appear last,
for example `-abcd VALUE`.

Variadic `*` and `+` parameters may be options, in which case the option is
repeatable, with each occurrence contributing one value:

```just
[arg('file', long)]
backup +file:
  scp {{file}} me@server.com:
```

```console
$ just backup --file FAQ.md --file GRAMMAR.md
scp FAQ.md GRAMMAR.md me@server.com:
```

As with positional variadic parameters, `+` options must be passed at least
once, whereas `*` options may be omitted.

The `[arg(ARG, value=VALUE, …)]`<sup>1.46.0</sup> attribute can be used with
`long` or `short` to make a parameter a flag which does not take a value.
`VALUE` may be an expression<sup>1.54.0</sup>.

In this `justfile`:

```just
[arg("bar", long="bar", value="hello")]
foo bar:
```

The parameter `bar` is given with the `--bar` option, but does not take a
value, and instead takes the value given in the `[arg]` attribute:

```console
$ just foo --bar
bar=hello
```

This is useful for unconditionally requiring a flag like `--force` on dangerous
commands.

A flag is optional if its parameter has a default:

```just
[arg("bar", long="bar", value="hello")]
foo bar="goodbye":
```

Causing it to receive the default when not passed in the invocation:

```console
$ just foo
bar=goodbye
```

### Avoiding Argument Splitting

Given this `justfile`:

```just
foo argument:
  touch {{argument}}
```

The following command will create two files, `some` and `argument.txt`:

```console
$ just foo "some argument.txt"
```

The user's shell will parse `"some argument.txt"` as a single argument, but
when `just` replaces `touch {{argument}}` with `touch some argument.txt`, the
quotes are not preserved, and `touch` will receive two arguments.

There are a few ways to avoid this: quoting, positional arguments, and exported
arguments.

#### Quoting

Quotes can be added around the `{{argument}}` interpolation:

```just
foo argument:
  touch '{{argument}}'
```

This preserves `just`'s ability to catch variable name typos before running,
for example if you were to write `{{argument}}`, but will not do what you want
if the value of `argument` contains single quotes.

#### Positional Arguments

The `positional-arguments` setting causes all arguments to be passed as
positional arguments, allowing them to be accessed with `$1`, `$2`, …, and
`$@`, which can then be double-quoted to avoid further splitting by the shell:

```just
set positional-arguments

foo argument:
  touch "$1"
```

This defeats `just`'s ability to catch typos, for example if you type `$2`
instead of `$1`, but works for all possible values of `argument`, including
those with double quotes.

#### Exported Arguments

All arguments are exported when the `export` setting is set:

```just
set export

foo argument:
  touch "$argument"
```

Or individual arguments may be exported by prefixing them with `$`:

```just
foo $argument:
  touch "$argument"
```

This defeats `just`'s ability to catch typos, for example if you type
`$argument`, but works for all possible values of `argument`, including those
with double quotes.

### Positional Arguments

If `positional-arguments` is `true`, recipe arguments will be passed as
positional arguments to commands. For shell recipes, argument `$0` will be the
name of the recipe.

For example, running this recipe:

```just
set positional-arguments

@foo bar:
  echo $0
  echo $1
```

Will produce the following output:

```console
$ just foo hello
foo
hello
```

When using an `sh`-compatible shell, such as `bash` or `zsh`, `$@` expands to
the positional arguments given to the recipe, starting from one. When used
within double quotes as `"$@"`, arguments including whitespace will be passed
on as if they were double-quoted. That is, `"$@"` is equivalent to `"$1" "$2"`…
When there are no positional parameters, `"$@"` and `$@` expand to nothing
(i.e., they are removed).

This example recipe will print arguments one by one on separate lines:

```just
set positional-arguments

@test *args='':
  bash -c 'while (( "$#" )); do echo - $1; shift; done' -- "$@"
```

Running it with _two_ arguments:

```console
$ just test foo "bar baz"
- foo
- bar baz
```

Positional arguments may also be turned on a per-recipe basis with the
`[positional-arguments]` attribute<sup>1.29.0</sup>:

```just
[positional-arguments]
@foo bar:
  echo $0
  echo $1
```

Note that PowerShell does not handle positional arguments in the same way as
other shells, so turning on positional arguments will likely break recipes that
use PowerShell.

If using PowerShell 7.4 or better, the `-CommandWithArgs` flag will make
positional arguments work as expected:

```just
set shell := ['pwsh.exe', '-CommandWithArgs']
set positional-arguments

print-args a b c:
  Write-Output @($args[1..($args.Count - 1)])
```

### Dependencies

Dependencies run before recipes that depend on them:

```just
a: b
  @echo A

b:
  @echo B
```

```
$ just a
B
A
```

In a given invocation of `just`, a recipe with the same arguments will only run
once, regardless of how many times it appears in the command-line invocation,
or how many times it appears as a dependency:

```just
a:
  @echo A

b: a
  @echo B

c: a
  @echo C
```

```
$ just a a a a a
A
$ just b c
A
B
C
```

Multiple recipes may depend on a recipe that performs some kind of setup, and
when those recipes run, that setup will only be performed once:

```just
build:
  cc main.c

test-foo: build
  ./a.out --test foo

test-bar: build
  ./a.out --test bar
```

```
$ just test-foo test-bar
cc main.c
./a.out --test foo
./a.out --test bar
```

Recipes in a given run are only skipped when they receive the same arguments:

```just
build:
  cc main.c

test TEST: build
  ./a.out --test {{TEST}}
```

```
$ just test foo test bar
cc main.c
./a.out --test foo
./a.out --test bar
```

#### Running Recipes at the End of a Recipe

Normal dependencies of a recipe always run before a recipe starts. That is to
say, the dependee always runs before the depender. These dependencies are
called "prior dependencies".

A recipe can also have subsequent dependencies, which run immediately after the
recipe and are introduced with an `&&`:

```just
a:
  echo 'A!'

b: a && c d
  echo 'B!'

c:
  echo 'C!'

d:
  echo 'D!'
```

…running _b_ prints:

```console
$ just b
echo 'A!'
A!
echo 'B!'
B!
echo 'C!'
C!
echo 'D!'
D!
```

#### Running Recipes in the Middle of a Recipe

`just` doesn't support running recipes in the middle of another recipe, but you
can call `just` recursively in the middle of a recipe. Given the following
`justfile`:

```just
a:
  echo 'A!'

b: a
  echo 'B start!'
  just c
  echo 'B end!'

c:
  echo 'C!'
```

…running _b_ prints:

```console
$ just b
echo 'A!'
A!
echo 'B start!'
B start!
echo 'C!'
C!
echo 'B end!'
B end!
```

This has limitations, since recipe `c` is run with an entirely new invocation
of `just`: Assignments will be recalculated, dependencies might run twice, and
command line arguments will not be propagated to the child `just` process.

### Parallelism

Dependencies may be run in parallel with the `[parallel]` attribute.

In this `justfile`, `foo`, `bar`, and `baz` will execute in parallel when
`main` is run:

```just
[parallel]
main: foo bar baz

foo:
  sleep 1

bar:
  sleep 1

baz:
  sleep 1
```

The number of simultaneously running recipes may be limited with the `--jobs`
option<sup>1.56.0</sup>. The `num_jobs()` function returns the number of jobs,
falling back to the empty list if `--jobs` was not passed.

GNU `parallel` may be used to run recipe lines concurrently:

```just
parallel:
  #!/usr/bin/env -S parallel --shebang --ungroup --jobs {{ num_cpus() }}
  echo task 1 start; sleep 3; echo task 1 done
  echo task 2 start; sleep 3; echo task 2 done
  echo task 3 start; sleep 3; echo task 3 done
  echo task 4 start; sleep 3; echo task 4 done
```

### Documentation Comments

Comments immediately preceding a recipe will appear in `just --list`:

```just
# build stuff
build:
  ./bin/build

# test stuff
test:
  ./bin/test
```

```console
$ just --list
Available recipes:
    build # build stuff
    test # test stuff
```

The `[doc]` attribute can be used to set or suppress a recipe's doc comment:

```just
# This comment won't appear
[doc('Build stuff')]
build:
  ./bin/build

# This one won't either
[doc]
test:
  ./bin/test
```

```console
$ just --list
Available recipes:
    build # Build stuff
    test
```

The value of `[doc]` may be a const expression<sup>1.56.0</sup>.

### Groups

Recipes and modules may be annotated with one or more group names:

```just
[group('lint')]
js-lint:
    echo 'Running JS linter…'

[group('rust recipes')]
[group('lint')]
rust-lint:
    echo 'Running Rust linter…'

[group('lint')]
cpp-lint:
  echo 'Running C++ linter…'

# not in any group
email-everyone:
    echo 'Sending mass email…'
```

Recipes are listed by group:

```
$ just --list
Available recipes:
```

> The README is long; the above is its first 40000 characters. Full content: https://github.com/casey/just
