---
part: pixi/advanced
title: Advanced tasks
description: Learn how to interact with pixi tasks
---
When building a package, you often have to do more than just run the code.
Steps like formatting, linting, compiling, testing, benchmarking, etc. are often part of a project.
With pixi tasks, this should become much easier to do.
Here are some quick examples
```toml title="pixi.toml"
[tasks]
# Commands as lists so you can also add documentation in between.
configure = { cmd = [
"cmake",
# Use the cross-platform Ninja generator
"-G",
"Ninja",
# The source is in the root directory
"-S",
".",
# We wanna build in the .build directory
"-B",
".build",
] }
# Depend on other tasks
build = { cmd = ["ninja", "-C", ".build"], depends_on = ["configure"] }
# Using environment variables
run = "python main.py $PIXI_PROJECT_ROOT"
set = "export VAR=hello && echo $VAR"
# Cross platform file operations
copy = "cp pixi.toml pixi_backup.toml"
clean = "rm pixi_backup.toml"
move = "mv pixi.toml backup.toml"
```
## Depends on
Just like packages can depend on other packages, our tasks can depend on other tasks.
This allows for complete pipelines to be run with a single command.
An obvious example is **compiling** before **running** an application.
Checkout our [`cpp_sdl` example](https://github.com/prefix-dev/pixi/tree/main/examples/cpp-sdl) for a running example.
In that package we have some tasks that depend on each other, so we can assure that when you run `pixi run start` everything is set up as expected.
```fish
pixi task add configure "cmake -G Ninja -S . -B .build"
pixi task add build "ninja -C .build" --depends-on configure
pixi task add start ".build/bin/sdl_example" --depends-on build
```
Results in the following lines added to the `pixi.toml`
```toml title="pixi.toml"
[tasks]
# Configures CMake
configure = "cmake -G Ninja -S . -B .build"
# Build the executable but make sure CMake is configured first.
build = { cmd = "ninja -C .build", depends_on = ["configure"] }
# Start the built executable
start = { cmd = ".build/bin/sdl_example", depends_on = ["build"] }
```
```shell
pixi run start
```
The tasks will be executed after each other:
- First `configure` because it has no dependencies.
- Then `build` as it only depends on `configure`.
- Then `start` as all it dependencies are run.
If one of the commands fails (exit with non-zero code.) it will stop and the next one will not be started.
With this logic, you can also create aliases as you don't have to specify any command in a task.
```shell
pixi task add fmt ruff
pixi task add lint pylint
```
```shell
pixi task alias style fmt lint
```
Results in the following `pixi.toml`.
```toml title="pixi.toml"
fmt = "ruff"
lint = "pylint"
style = { depends_on = ["fmt", "lint"] }
```
Now run both tools with one command.
```shell
pixi run style
```
## Working directory
Pixi tasks support the definition of a working directory.
`cwd`" stands for Current Working Directory.
The directory is relative to the pixi package root, where the `pixi.toml` file is located.
Consider a pixi project structured as follows:
```shell
├── pixi.toml
└── scripts
└── bar.py
```
To add a task to run the `bar.py` file, use:
```shell
pixi task add bar "python bar.py" --cwd scripts
```
This will add the following line to `pixi.toml`:
```toml title="pixi.toml"
[tasks]
bar = { cmd = "python bar.py", cwd = "scripts" }
```
## Our task runner: deno_task_shell
To support the different OS's (Windows, OSX and Linux), pixi integrates a shell that can run on all of them.
This is [`deno_task_shell`](https://deno.land/manual@v1.35.0/tools/task_runner#built-in-commands).
The task shell is a limited implementation of a bourne-shell interface.
### Built-in commands
Next to running actual executable like `./myprogram`, `cmake` or `python` the shell has some built-in commandos.
- `cp`: Copies files.
- `mv`: Moves files.
- `rm`: Remove files or directories.
Ex: `rm -rf [FILE]...` - Commonly used to recursively delete files or directories.
- `mkdir`: Makes directories.
Ex. `mkdir -p DIRECTORY...` - Commonly used to make a directory and all its parents with no error if it exists.
- `pwd`: Prints the name of the current/working directory.
- `sleep`: Delays for a specified amount of time.
Ex. `sleep 1` to sleep for 1 second, `sleep 0.5` to sleep for half a second, or `sleep 1m` to sleep a minute
- `echo`: Displays a line of text.
- `cat`: Concatenates files and outputs them on stdout. When no arguments are provided, it reads and outputs stdin.
- `exit`: Causes the shell to exit.
- `unset`: Unsets environment variables.
- `xargs`: Builds arguments from stdin and executes a command.
### Syntax
- **Boolean list:** use `&&` or `||` to separate two commands.
- `&&`: if the command before `&&` succeeds continue with the next command.
- `||`: if the command before `||` fails continue with the next command.
- **Sequential lists:** use `;` to run two commands without checking if the first command failed or succeeded.
- **Environment variables:**
- Set env variable using: `export ENV_VAR=value`
- Use env variable using: `$ENV_VAR`
- unset env variable using `unset ENV_VAR`
- **Shell variables:** Shell variables are similar to environment variables, but won’t be exported to spawned commands.
- Set them: `VAR=value`
- use them: `VAR=value && echo $VAR`
- **Pipelines:** Use the stdout output of a command into the stdin a following command
- `|`: `echo Hello | python receiving_app.py`
- `|&`: use this to also get the stderr as input.
- **Command substitution:** `$()` to use the output of a command as input for another command.
- `python main.py $(git rev-parse HEAD)`
- **Negate exit code:** `! ` before any command will negate the exit code from 1 to 0 or visa-versa.
- **Redirects:** `>` to redirect the stdout to a file.
- `echo hello > file.txt` will put `hello` in `file.txt` and overwrite existing text.
- `python main.py 2> file.txt` will put the `stderr` output in `file.txt`.
- `python main.py &> file.txt` will put the `stderr` **and** `stdout` in `file.txt`.
- `echo hello > file.txt` will append `hello` to the existing `file.txt`.
- **Glob expansion:** `*` to expand all options.
- `echo *.py` will echo all filenames that end with `.py`
- `echo **/*.py` will echo all filenames that end with `.py` in this directory and all descendant directories.
- `echo data[0-9].csv` will echo all filenames that have a single number after `data` and before `.csv`
More info in [`deno_task_shell` documentation](https://deno.land/manual@v1.35.0/tools/task_runner#task-runner).