just
is a handy way to save and run project-specific commands.
This readme is also available as a book.
(δΈζζζ‘£ε¨ θΏι, εΏ«ηθΏζ₯!)
Commands, called recipes, are stored in a file called justfile
with syntax inspired by make
:
You can then run them with just RECIPE
:
$ 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 ofmake
's complexity and idiosyncrasies. No need for.PHONY
recipes! -
Linux, MacOS, and Windows are supported with no additional dependencies. (Although if your system doesn't have an
sh
, you'll need to choose a different shell.) -
Errors are specific and informative, and syntax errors are reported along with their source context.
-
Recipes can accept command line arguments.
-
Wherever possible, errors are resolved statically. Unknown recipes and circular dependencies are reported before anything runs.
-
just
loads.env
files, making it easy to populate environment variables. -
Recipes can be listed from the command line.
-
Command line completion scripts are available for most popular shells.
-
Recipes can be written in arbitrary languages, like Python or NodeJS.
-
just
can be invoked from any subdirectory, not just the directory that contains thejustfile
. -
And much more!
If you need help with just
please feel free to open an issue or ping me on Discord. Feature requests and bug reports are always welcome!
just
should run on any system with a reasonable sh
, including Linux, MacOS, and the BSDs.
On Windows, just
works with the sh
provided by Git for Windows, GitHub Desktop, or Cygwin.
If you'd rather not install sh
, you can use the shell
setting to use the shell of your choice.
Like PowerShell:
# use PowerShell instead of sh:
set shell := ["powershell.exe", "-c"]
hello:
Write-Host "Hello, world!"
β¦or cmd.exe
:
# 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 S1 and later, and cmd.exe
is quite fiddly, so PowerShell is recommended for most Windows users.)
Operating System | Package Manager | Package | Command |
---|---|---|---|
Various | Cargo | just | cargo install just |
Microsoft Windows | Scoop | just | scoop install just |
Various | Homebrew | just | brew install just |
macOS | MacPorts | just | port install just |
Arch Linux | pacman | just | pacman -S just |
Various | Nix | just | nix-env -iA nixpkgs.just |
NixOS | Nix | just | nix-env -iA nixos.just |
Solus | eopkg | just | eopkg install just |
Void Linux | XBPS | just | xbps-install -S just |
FreeBSD | pkg | just | pkg install just |
Alpine Linux | apk-tools | just | apk add just |
Fedora Linux | DNF | just | dnf install just |
Gentoo Linux | Portage | dm9pZCAq/sys-devel/just |
eselect repository enable dm9pZCAq emerge --sync dm9pZCAq emerge sys-devel/just
|
Various | Conda | just | conda install -c conda-forge just |
Microsoft Windows | Chocolatey | just | choco install just |
Various | Snap | just | snap install --edge --classic just |
Various | asdf | just |
asdf plugin add just asdf install just <version>
|
Debian and Ubuntu derivatives | MPR | just |
git clone 'https://mpr.makedeb.org/just' cd just makedeb -si
|
Debian and Ubuntu derivatives | Prebuilt-MPR | just |
You must have the Prebuilt-MPR set up on your system in order to run this command.sudo apt install just
|
Pre-built binaries for Linux, MacOS, and Windows can be found on the releases page.
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
:
curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to DEST
For example, to install just
to ~/bin
:
# 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 shells initialization file,
# e.g. `~/.bashrc` or `~/.zshrc`
export PATH="$PATH:$HOME/bin"
# just should now be executable
just --help
extractions/setup-just can be used to install just
in a GitHub Actions workflow.
Example usage:
- uses: extractions/setup-just@v1
with:
just-version: 0.8 # optional semver specification, otherwise latest
An RSS feed of just
releases is available here.
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 set up process for their project as easy as possible.
For more information, see the just-install README file.
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 gated behind the --unstable
flag. Features enabled by --unstable
may change in backwards incompatible ways at any time.
justfile
syntax is close enough to make
that you may want to tell your editor to use make
syntax highlighting for just
.
The vim-just plugin provides syntax highlighting for justfile
s.
Install it with your favorite package manager, like Plug:
call plug#begin()
Plug 'NoahTheDuke/vim-just'
call plug#end()
Or with Vim's built-in package support:
mkdir -p ~/.vim/pack/vendor/start
cd ~/.vim/pack/vendor/start
git clone https://github.com/NoahTheDuke/vim-just.git
vim-just
is also available from vim-polyglot, a multi-language Vim plugin.
tree-sitter-just is an Nvim Treesitter plugin for Neovim.
Vim's built-in makefile syntax highlighting isn't perfect for justfile
s, but it's better than nothing. You can put the following in ~/.vim/filetype.vim
:
if exists("did_load_filetypes")
finish
endif
augroup filetypedetect
au BufNewFile,BufRead justfile setf make
augroup END
Or add the following to an individual justfile
to enable make
mode on a per-file basis:
# vim: set ft=make :
just-mode provides syntax highlighting and automatic indentation of justfile
s. It is available on MELPA as just-mode.
justl 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:
# Local Variables:
# mode: makefile
# End:
An extension for VS Code by skellock is available here (repository).
You can install it from the command line by running:
code --install-extension skellock.just
A plugin for JetBrains IDEs by linux_china is available here.
Kakoune supports justfile
syntax highlighting out of the box, thanks to TeddyDD.
A syntax file for Sublime Text written by TonioGela is available in extras/just.sublime-syntax.
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.
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.
Once just
is installed and working, create a file named justfile
in the root of your project with the following contents:
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 file 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
.
Running just
with no arguments runs the first recipe in the justfile
:
$ just
echo 'This is a recipe!'
This is a recipe!
One or more arguments specify the recipe(s) to run:
$ 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:
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
:
build:
cc main.c foo.c bar.c -o main
test: build
./test
sloc:
@echo "`wc -l *.c` lines of code"
$ 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:
$ 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:
$ just test build
cc main.c foo.c bar.c -o main
./test
testing⦠all tests passed!
A variety of example justfile
s can be found in the examples directory.
When just
is invoked without a recipe, it runs the first recipe in the justfile
. This recipe might be the most frequently run command in the project, like running the tests:
test:
cargo test
You can also use dependencies to run multiple recipes by default:
default: lint build test
build:
echo Buildingβ¦
test:
echo Testingβ¦
lint:
echo Lintingβ¦
If no recipe makes sense as the default recipe, you can add a recipe to the beginning of your justfile
that lists the available recipes:
default:
just --list
Recipes can be listed in alphabetical order with just --list
:
$ just --list
Available recipes:
build
test
deploy
lint
just --summary
is more concise:
$ just --summary
build test deploy lint
Pass --unsorted
to print recipes in the order they appear in the justfile
:
test:
echo 'Testing!'
build:
echo 'Building!'
$ just --list --unsorted
Available recipes:
test
build
$ just --summary --unsorted
test build
If you'd like just
to default to listing the recipes in the justfile
, you can use this as your default recipe:
default:
@just --list
Note that you may need to add --justfile {{justfile()}}
to the line above above. Without it, if you executed just -f /some/distant/justfile -d .
or just -f ./non-standard-justfile
, the plain just --list
inside the recipe would not necessarily use the file you provided. It would try to find a justfile in your current path, maybe even resulting in a No justfile found
error.
The heading text can be customized with --list-heading
:
$ just --list --list-heading $'Cool stuffβ¦\n'
Cool stuffβ¦
test
build
And the indentation can be customized with --list-prefix
:
$ just --list --list-prefix Β·Β·Β·Β·
Available recipes:
Β·Β·Β·Β·test
Β·Β·Β·Β·build
The argument to --list-heading
replaces both the heading and the newline following it, so it should contain a newline if non-empty. It works this way so you can suppress the heading line entirely by passing the empty string:
$ just --list --list-heading ''
test
build
Aliases allow recipes to be invoked with alternative names:
alias b := build
build:
echo 'Building!'
$ just b
build
echo 'Building!'
Building!
Settings control interpretation and execution. Each setting may be specified at most once, anywhere in the justfile
.
For example:
set shell := ["zsh", "-cu"]
foo:
# this line will be run as `zsh -cu 'ls **/*.txt'`
ls **/*.txt
Name | Value | Description |
---|---|---|
allow-duplicate-recipes |
boolean | Allow recipes appearing later in a justfile to override earlier recipes with the same name. |
dotenv-load |
boolean | Load a .env file, if present. |
export |
boolean | Export all variables as environment variables. |
positional-arguments |
boolean | Pass positional arguments. |
shell |
[COMMAND, ARGSβ¦] |
Set the command used to invoke recipes and evaluate backticks. |
windows-powershell |
boolean | Use PowerShell on Windows as default shell. |
Boolean settings can be written as:
set NAME
Which is equivalent to:
set NAME := true
If allow-duplicate-recipes
is set to true
, defining multiple recipes with the same name is not an error and the last definition is used. Defaults to false
.
set allow-duplicate-recipes
@foo:
echo foo
@foo:
echo bar
$ just foo
bar
If dotenv-load
is true
, a .env
file will be loaded if present. Defaults to false
.
The export
setting causes all just
variables to be exported as environment variables. Defaults to false
.
set export
a := "hello"
@foo b:
echo $a
echo $b
$ just foo goodbye
hello
goodbye
If positional-arguments
is true
, recipe arguments will be passed as positional arguments to commands. For linewise recipes, argument $0
will be the name of the recipe.
For example, running this recipe:
set positional-arguments
@foo bar:
echo $0
echo $1
Will produce the following output:
$ 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:
set positional-arguments
@test *args='':
bash -c 'while (( "$#" )); do echo - $1; shift; done' -- "$@"
Running it with two arguments:
$ just test foo "bar baz"
- foo
- bar baz
The shell
setting controls the command used to invoke recipe lines and backticks. Shebang recipes are unaffected.
# use python3 to execute recipe lines and backticks
set shell := ["python3", "-c"]
# use print to capture result of evaluation
foos := `print("foo" * 4)`
foo:
print("Snake snake snake snake.")
print("{{foos}}")
just
passes the command to be executed as an argument. Many shells will need an additional flag, often -c
, to make them evaluate the first argument.