Documentation Index
Fetch the complete documentation index at: https://mintlify.com/cachix/devenv/llms.txt
Use this file to discover all available pages before exploring further.
Most projects accumulate a collection of shell scripts over time — build helpers, migration runners, deployment utilities. devenv lets you define these scripts directly in devenv.nix so they are versioned with your project, available to every developer who enters the shell, and have guaranteed access to all the packages and environment variables your project declares.
Defining a Script
Use scripts.<name>.exec to define a named script. The script is exposed as an executable in your shell as soon as you run devenv shell:
{ pkgs, ... }:
{
packages = [ pkgs.curl pkgs.jq ];
scripts.silly-example.exec = ''
curl "https://httpbin.org/get?$1" | jq '.args'
'';
}
Because scripts are activated alongside the environment, any packages in packages are available by name:
$ devenv shell
Building shell ...
Entering shell ...
(devenv) $ silly-example foo=1
{
"foo": "1"
}
Passing Arguments
Scripts receive command-line arguments normally. Use $1, $2, etc. for positional arguments, or $@ to forward all arguments:
{
scripts.foo.exec = ''
npx @foo/cli "$@";
'';
}
Runtime Packages
Sometimes you need a package only when a specific script runs, without adding it to the global environment. Use the packages attribute on the script itself:
{ pkgs, ... }:
{
scripts.analyze-json = {
exec = ''
# Both curl and jq are available when this script runs
curl "https://httpbin.org/get?$1" | jq '.args'
'';
packages = [ pkgs.curl pkgs.jq ];
description = "Fetch and analyze JSON";
};
}
The packages attribute ensures these tools are in the script’s PATH without polluting the global development environment.
Pinning Packages Inside Scripts
For maximum reproducibility, interpolate package store paths directly into the script. This pins the exact binary used, regardless of what is on PATH:
{ pkgs, ... }:
{
scripts.silly-example.exec = ''
${pkgs.curl}/bin/curl "https://httpbin.org/get?$1" | ${pkgs.jq}/bin/jq '.args'
'';
}
When a Nix package is interpolated in a string, Nix substitutes the absolute path to that package in the Nix store.
$ devenv shell
Building shell ...
Entering shell ...
(devenv) $ silly-example foo=1
{
"foo": "1"
}
Scripts in Other Languages
The package attribute lets you run a script using any interpreter. Optionally set binary if the interpreter binary name differs from the package name:
{ pkgs, config, lib, ... }:
{
scripts.python-hello = {
exec = ''
print("Hello, world!")
'';
package = config.languages.python.package;
description = "hello world in Python";
};
scripts.nushell-greet = {
exec = ''
def greet [name] {
["hello" $name]
}
greet "world"
'';
package = pkgs.nushell;
binary = "nu";
description = "Greet in Nu Shell";
};
}
Loading Scripts from External Files
The exec attribute also accepts a path, which lets you keep longer scripts in separate files:
{
scripts.file-example = {
exec = ./file-script.sh;
description = "Script loaded from external file";
};
}
Listing Scripts in enterShell
The description field on each script combines well with enterShell to print a help menu when developers enter the project shell:
{ pkgs, config, lib, ... }:
{
scripts.python-hello = {
exec = ''
print("Hello, world!")
'';
package = config.languages.python.package;
description = "hello world in Python";
};
scripts.nushell-greet = {
exec = ''
def greet [name] {
["hello" $name]
}
greet "world"
'';
package = pkgs.nushell;
binary = "nu";
description = "Greet in Nu Shell";
};
scripts.file-example = {
exec = ./file-script.sh;
description = "Script loaded from external file";
};
enterShell = ''
echo
echo 🦾 Helper scripts you can run to make your development richer:
echo 🦾
${pkgs.gnused}/bin/sed -e 's| |••|g' -e 's|=| |' <<EOF | ${pkgs.util-linuxMinimal}/bin/column -t | ${pkgs.gnused}/bin/sed -e 's|^|🦾 |' -e 's|••| |g'
${lib.generators.toKeyValue {} (lib.mapAttrs (name: value: value.description) config.scripts)}
EOF
echo
'';
}
When you enter the shell, the script list is printed automatically:
$ devenv shell
Building shell ...
Entering shell ...
🦾 Helper scripts you can run to make your development richer:
🦾
🦾 python-hello Hello world in Python
🦾 nushell-greet Greet in Nu Shell
🦾 file-example Script loaded from external file
(devenv) $
For operations that need to run when entering the shell (such as database migrations or code generation), consider using tasks with the before attribute instead of enterShell. Tasks provide better control over execution order and dependencies.
Scripts Option Reference
| Attribute | Type | Description |
|---|
exec | string or path | The script body, or a path to an external script file |
description | string | Human-readable description shown in help menus |
packages | list of packages | Packages added to PATH only when this script runs |
package | package | Interpreter package (for non-shell scripts) |
binary | string | Binary name within package (defaults to package name) |