- It doesn't scale to an arbitrary number of packages (you would have to type out each package name each time).
- It doesn't (ergonomically) allow you any further customization of your shell environment.
A better solution is to create our shell environment from a `shell.nix` file.
## A basic `shell.nix` file
The `nix-shell` command by default looks for a file called `shell.nix` in the current directory and tries to build a shell environment by evaluating the Nix expression in this file.
So, if you properly describe the shell environment you want in a `shell.nix` file, you can enter it with just the `nix-shell` command without any further arguments.
No more specifying packages on the command line.
Here's what a basic `shell.nix` looks like that installs Python 3.10 as before:
If you save this into a file called `shell.nix` and call `nix-shell` in the directory containing this `shell.nix` file, you'll enter a shell with Python 3 installed.
`nix-shell` was originally conceived as a way to construct a shell environment containing the tools needed to *develop software*; only later was it widely used as a general way to construct temporary environments for other purposes. Also note that `mkShell` is a [wrapper around `mkDerivation`](https://nixos.org/manual/nixpkgs/stable/#sec-pkgs-mkShell) so strictly speaking you can provide any attributes to `mkShell` that you could to `mkDerivation` such as `buildInputs`. However, the `packages` attribute provided to `mkShell` is an alias for `buildInputs`, so you shouldn't need to provide both `packages` and `buildInputs`.
It's common to want to automatically export certain environment variables when you enter a shell environment.
For example, you could have a database that depends on an environment variable to set the default authentication credentials during development.
Setting an environment variable in via `shell.nix` is trivial.
Any attribute in the `mkShell` function call that `mkShell` doesn't recognize as a reserved attribute name will be set to an environment variable in the shell environment.
The attributes that are reserved are listed in the [Nixpkgs manual][mkshell_attrs] and include `packages`, `name`, and several others.
For example, the shell prompt format for most shells is set by the `PS1` environment variable, but `nix-shell` already overrides this by default, and will ignore a `PS1` attribute listed in `env`.
If you _really_ need to override these protected environment variables you can use the `shellHook` feature discussed in the next section and `export MYVAR="value"` in the hook script.
It's generally discouraged to set environment variables this way.
You may want to perform some initialization before entering the shell environment (for example, maybe you want to ensure that a file exists).
Commands you'd like to run before entering the shell environment can be placed in the `shellHook` attribute of the attribute set provided to the `mkShell` function.
To ensure that a file `should_exist.txt` exists, the `shell.nix` file would look like this: