(ad-hoc-envs)= # Ad hoc developer environments Assuming you have {ref}`Nix installed `, you can use it to download packages and create new **shell environments** that use these packages. This is a great way to play with Nix tooling and see some of its potential. ## What is a shell environment? A shell environment gives you access to the exact versions of packages specified by Nix. A hello world example: ```shell-session $ hello The program ‘hello’ is currently not installed. $ nix-shell -p hello [nix-shell:~]$ hello Hello, world! [nix-shell:~]$ exit exit $ hello The program ‘hello’ is currently not installed. ``` Here we used the `-p` (packages) flag to specify that we needed the `hello` dependency. Nix found it, downloaded it, and made it available in a shell environment. ## When are shell environments useful? If you'd like **to use a tool that you do not have installed**. You can use the tool without having to install the software. If you'd like **to try a tool for a few minutes**. For example, there's a shiny new tool for writing presentation slides. If you'd like **to give someone else a one-liner to install a set of tools** and you want this to work on all Linux distributions and MacOS. If you'd like **to provide a script that is reproducible**, meaning it will also provide any tools that it depends on. ## Searching package attribute names What can you put in a shell environment? Anything that's in the [official package list](https://nixos.org/nixos/packages.html) can become part of the shell environment. You can search the package list using: ```shell-session $ nix-env -qaP git gitAndTools.gitFull git-2.25.0 gitMinimal git-2.25.0 ``` The first column is the {term}`attribute name` and the second is the {term}`package name` and its version. Once you are comfortable doing this, you can add other things too. For example, packages of your own, or custom shell aliases. :::{note} The query you use for searching packages is a regex, so be aware when it comes to special characters. ::: ## Ad hoc shell environments Once you have the {term}`attribute name` for packages, you can start a shell: ```shell-session $ nix-shell -p gitMinimal vim nano joe these paths will be fetched (44.16 MiB download, 236.37 MiB unpacked): ... /nix/store/fsn35pc8njnimgn2sn26dlsyxya1wssb-vim-8.2.0013 /nix/store/wdqjszpr5dlys53d79fym6rv9vyyz29h-joe-4.6 /nix/store/hx63qkip16i4wifaqgxwrrmxj4az53h1-git-2.25.0 [nix-shell:~]$ git --version git version 2.25.0 [nix-shell:~]$ which git /nix/store/hx63qkip16i4wifaqgxwrrmxj4az53h1-git-2.25.0/bin/git ``` Note that even if you had Git installed before, in the shell, only the exact version installed by Nix is used. Press `CTRL-D` to exit the shell and those packages won't be available anymore. ## Beyond tooling: Python libraries `nix-shell` provides a bunch of other bash variables from packages specified. Let's try a quick example using Python and `$PYTHONPATH`: ```shell-session $ nix-shell -p 'python38.withPackages (packages: [ packages.django ])' ... [nix-shell:~]$ python -c 'import django; print(django)' ``` We create an ad hoc environment with `$PYTHONPATH` set and `python` available, along with the `django` package. The `-p` argument can handle more than attribute names. You can use a full Nix expression, but we'll cover that in later tutorials. ## Towards reproducibility Even running in these basic Nix shells, if you handed over these commands to another developer, they could get different results. These shell environments are **really convenient**, but they are not **perfectly reproducible** in this form. What do we mean by reproducible? A fully reproducible example would give exactly the same results no matter **when** or **on what machine** you run the command. The environment provided would be identical each time. Nix also offers fully reproducible environments, which it calls pure environments. The following is a fully reproducible example and something that different colleagues with different machines, for example, could share. ```shell-session $ nix-shell --pure -p git -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/2a601aafdc5605a5133a2ca506a34a3a73377247.tar.gz [nix-shell:~]$ git --version git version 2.33.1 ``` There are two things going on here: 1. The `--pure` flag makes sure that the bash environment from your system is not inherited. That means only the `git` that Nix installed is available inside the shell. This is useful for one-liners and scripts that run, for example, within a CI environment. While developing, however, we'd like to have our editor around and a bunch of other things. Therefore we might skip the flag for development environments but use it in build ones. 2. The `-I` flag pins the Nixpkgs revision to an **exact Git revision**, leaving no doubt about which exact version of Nix packages will be used. ## References - [Nix manual: `nix-shell`](https://nixos.org/manual/nix/stable/command-ref/nix-shell) or `man nix-shell` ## Next steps We've only covered the bare essentials of Nix here. Once you're comfortable with these examples, take a look at: - {ref}`reproducible-scripts` to see how to use `nix-shell` for reproducible scripts. - {ref}`reading-nix-language` to learn about the Nix language, which is used to declare packages and configurations. - {ref}`pinning-nixpkgs` to see different ways to import Nixpkgs. - {ref}`declarative-reproducible-envs` to create reproducible shell environments with a declarative configuration file. - [Garbage Collection](https://nixos.org/manual/nix/stable/package-management/garbage-collection.html) – free up storage used by the programs made available through Nix - To quickly setup a Nix project read through [Getting started Nix template](https://github.com/nix-dot-dev/getting-started-nix-template).