The command nix-shell will build the dependencies of the specified derivation, but not the derivation itself.
It will then start an interactive shell in which all environment variables defined by the derivation path have been set to their corresponding values, and the script $stdenv/setup has been sourced. This is useful for reproducing the environment of a derivation for development.
Def: nix-shell, translated
nix-shell will start an interactivebash shell, in the same directory that it is being run from.
This shell will have its ENV set appropriately so that all the packages in the shell definition are available.
nix-shell to use a package without installing it globally
$ which rg
rg not found
$ nix-shell -p ripgrep
[nix-shell:~]$ which rg
/nix/store/rw24lqk4ls1b90k1jj0j1ld05kgqb8ac-ripgrep-11.0.2/bin/rg
nix-shell --packages
$ nix-shell -p packagename# or
$ nix-shell --packages packagename
Starts a nix-shell that has the package available in its $PATH
nix-shell --run
$ nix-shell -p ripgrep --run "rg foo"
Executes the given command in a non-interactive shell
nix-shell --pure
$ which wget
/usr/bin/wget$ nix-shell --pure-pcurl
[nix-shell:~]$ which wget
which not found
If this flag is specified, the environment is almost entirely cleared before the interactive shell is started.
A simple shell.nix
# save this as shell.nixwith (import <nixpkgs> {});
mkShell {
buildInputs = [
ripgrep
];
}
$ nix-shell
[nix-shell:~]$ rg foo
# ... WIN
Adding shellHook
with (import <nixpkgs> {});
mkShell {
shellHook = ''
alias ll="ls -l"
export FOO=bar
'';
}
In the "Nix way" a package and its dependecies are "reproducible", the final derivation we build is alwasy gonna be the same because the inputs will always be the same.
Languages like ruby, js and others don't naturally have that
The Nix ecosystem has a few ways to work around this problem
For Ruby it's called bundix
bundix runs against your Gemfile and generates a nix derivation for each gem in your project
ruby and bundix #2
run bundix -l
source gemset.nix in your shell.nix
use the nix-shell
with (import <nixpkgs> {});
letgems = bundlerEnv {
name = "your-package";
inherit ruby;
gemdir = ./.;
};
in mkShell {
buildInputs = [gems ruby];
}
Beyond bundix
Similar solutions exist for Elixir, JavaScript and other languages
A python example
with (import <nixpkgs> {});
letmy-python-packages = python-packages: with python-packages; [
pandas
requests
# other python packages you want
];
python-with-my-packages = python3.withPackages my-python-packages;
in
mkShell {
buildInputs = [
python-with-my-packages
];
shellHook = ''
mkdir -p .nix-node
export NODE_PATH=$PWD/.nix-node
export NPM_CONFIG_PREFIX=$PWD/.nix-node
export PATH=$NODE_PATH/bin:$PATH
'';
}
withimport <nixpkgs> {};
letsrc = fetchFromGitHub {
owner = "mozilla";
repo = "nixpkgs-mozilla";
rev = "9f35c4b09fd44a77227e79ff0c1b4b6a69dff533";
sha256 = "18h0nvh55b5an4gmlgfbvwbyqj91bklf1zymis6lbdh75571qaz0";
};
inwithimport"${src.out}/rust-overlay.nix" pkgs pkgs;
stdenv.mkDerivation {
name = "rust-env";
buildInputs = [
# Note: to use use stable, just replace `nightly` with `stable`
latest.rustChannels.nightly.rust
# Add some extra dependencies from `pkgs`
pkgconfig openssl
];
# Set Environment Variables (<-- another way to do this)RUST_BACKTRACE = 1;
}
This pretty much guarantees that so long as you specify all the dependencies, and don't accidentally rely on something coming from the OS, everyone will have the same setup.
Extending a shared shell - shell.nix
When sharing shell.nix it's nice to allow for customization