# numtide devshell for project-scoped Nix environments

> numtide/devshell provides project-specific developer environments through Nix, direnv, TOML, or Nix expressions. It is aimed at teams that want reproducible development dependencies without importing the full compiler environment used by mkShell.

**numtide/devshell** — Per project developer environments

- Repository: https://github.com/numtide/devshell
- Website: https://numtide.github.io/devshell/
- Stars: 1,570 · Forks: 88
- Language: Nix
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/numtide-devshell

## What numtide/devshell changes for a repository

numtide/devshell addresses dependency setup at the repository boundary. Its stated goal is to let a new employee, transferred team member, or outside contributor clone a project and obtain its development dependencies in about ten minutes. The project is intended for repositories that need repeatable local tooling, especially when contributors work across several languages or services.

The central design choice is a lean shell. The README contrasts this with `pkgs.stdenv.mkDerivation` and `pkgs.mkShell`, which build on `stdenv` and can bring in compiler-related variables such as `CC`, `CXX`, `NIX_CC`, `NIX_CFLAGS_COMPILE`, and many build phases. devshell instead starts from `builtins.derivation`. According to the README, this produces a smaller set of exported variables when entering through direnv, with examples such as `DEVSHELL_DIR`, `PRJ_ROOT`, `PRJ_DATA_DIR`, `IN_NIX_SHELL`, and `NIXPKGS_PATH`.

That distinction matters for projects where the development command set is known but the full build-system environment is unnecessary. It does not mean that packages are isolated from their own transitive dependencies. The documented mechanism is about the shell composition, so teams still need to confirm that the tools they import behave correctly without the variables they expect from `stdenv`.

## Nix, direnv, and TOML are the configuration paths

devshell is designed to remain compatible with `nix-shell`, `direnv`, and Nix flakes. That compatibility gives a project several ways to consume the same environment definition. A contributor can enter a shell directly with Nix, allow direnv to load it when changing directories, or run a command through a flake application without manually entering an interactive shell.

The README says that project members who prefer not to write Nix can define the common cases in a TOML file. The repository includes `devshell.toml`, and the README states that TOML should handle 80 percent of use cases, with Nix as a fallback. This gives teams a gradual adoption path: contributors who know Nix can use a Nix expression, while others can work from the simpler TOML representation.

The generated environment also includes several variables with defined project roles. `DEVSHELL_DIR` contains the programs, `PRJ_ROOT` points to the project root, and `PRJ_DATA_DIR` points to `$PRJ_ROOT/.data` by default for runtime data. `NIXPKGS_PATH` identifies the nixpkgs source. In direnv mode, the README says these values replace a much larger collection of compiler, build, and Nix variables.

The repository also contains `flake-module.nix`, `modules/`, `nix/`, `overlay.nix`, `shell.nix`, and `default.nix`. Those files indicate that the implementation is distributed as a Nix project with modules and packaging support, rather than as a standalone binary installer. The README does not document a separate platform installer, version selector, or compatibility matrix, so operating-system coverage should be checked in the project documentation before adoption.

## A first devshell invocation with the documented Nix commands

The README gives two runnable examples. The first executes the project's own devshell as a Nix application and passes the `hello` command. This is a useful first check because it exercises the flake application path without requiring the reader to infer an application name or command line.

The documented command is:

```sh
nix run 'github:numtide/devshell' -- hello
```

The reader should expect the command output to come from the devshell application rather than from an invented setup script. The README describes `hello` as a command that prints `hello` and also lists `menu` as a utility that prints the available command menu. The exact installation instructions for adding devshell to another project are not present in the README excerpt, so there is no reliable standalone `npm`, `pip`, or binary installation command to reproduce here.

For an existing project that already has a shell, the README documents the standard Nix entry points `nix-shell` and `nix develop`. It also shows the direnv export result after loading, which provides a concrete way to inspect whether the expected environment appeared. A contributor should not assume that entering a shell changes files in the repository. The documented variables define paths and runtime data locations, while `PRJ_DATA_DIR` defaults to a directory under the project root.

## CI dependency capture and runnable project commands

devshell supports a workflow where the development dependencies represented by a shell can be captured for CI or a binary cache. The README gives this command:

```sh
nix-build shell.nix | cachix push <mycache>
```

The command builds `shell.nix` and sends the resulting Nix store paths to a cache named by `<mycache>`. The README presents this as useful when a CI and binary-cache setup already exists. It does not explain how to create the cache, authenticate to `cachix`, or configure a CI provider, so those parts remain the team's responsibility. The documented operation is a transfer of the built outputs, not a general-purpose CI runner integration.

The project can also expose commands as runnable Nix applications. The syntax is:

```nix
nix run '.#<myapp>' -- <devshell-command> <and-args>
```

This permits a command defined by a devshell to run without first entering `nix-shell` or `nix develop`. That is useful for repository automation, such as invoking a formatter or linter through the same package set used during local development. The application name and command must exist in the relevant devshell configuration. The README does not say how arbitrary scripts are discovered or whether every package command is exposed automatically.

This feature is an alternative approach to a conventional task runner. Instead of relying only on a local script wrapper, the command is represented as a Nix application and selected through `nix run`. The trade-off is that application names and package outputs must be known by the caller.

## MOTD, command discovery, and completion behavior

Entering a project with `nix-shell` or `nix develop` causes devshell's `mkShell` to print a welcome message, according to the README. The displayed menu groups available programs under labels such as `general commands`, `formatters`, `linters`, and `utilites`. The example includes `hello`, `menu`, `nixpkgs-fmt`, `golangci-lint`, and `hub`.

The project provides a `menu` function for listing available programs. The README is candid that it is not certain whether the utility functions are useful yet, which is a useful indicator of the project's experimental character. A command list can help contributors discover tools that are not obvious from the project README, but it does not establish that the tools are installed for every operating system or that every displayed program is appropriate for a particular task.

Bash completion is loaded automatically when packages contain Bash completions, and the README says this behavior applies in `nix-shell` and `nix develop` modes. The project therefore expects Bash completion data to be detectable in the package set. The TODO section says that support for other shells needs work, although it also states that support is already available in direnv mode. That distinction leaves an important boundary for non-Bash users: the documented automatic completion path is Bash-oriented, and the README does not claim equivalent completion loading for Zsh, fish, or PowerShell.

The MOTD also makes configuration errors visible in a practical way. If a package is missing from the expected menu, or if a command exists but lacks completion, the printed environment gives the contributor a place to start investigating. It is not a substitute for a `doctor` command, which remains listed in the TODO section.

## Limitations of an unstable Nix shell project

The README labels the project `STATUS: unstable`, and its TODO list explicitly includes missing documentation, incomplete integration tests, lazy dependency support, a doctor or Nix version check, and better shell support. Those are concrete limitations rather than editorial qualifications. Users should not treat the listed features as a stability guarantee.

The lean environment is also a compatibility decision. A package or build process that assumes `stdenv` variables may fail because `mkShell` does not export the same compiler and build variables. The README itself explains that `stdenv` can make it difficult to select a specific C compiler. devshell solves that by avoiding that broader base, but the resulting shell may be unsuitable for projects that genuinely need the standard derivation environment. In that case, `pkgs.mkShell` or a conventional Nix shell is the more direct choice.

There is no documented rollback procedure, migration guide, supported-version policy, or release history in the project information. The repository has no GitHub releases, so the project cannot be assessed from a release cadence there. Its last push was on 2026-10-13, but a recent push does not establish a stable API or completed feature set. The absence of release artifacts also means adoption should account for evaluating the repository's current documentation and tests directly.

The MIT license permits broad use of the project under its terms, but teams still need to inspect `LICENSE` and any separate licensing for Nix packages, dependencies, or cached binaries used in their deployment. The MIT status of devshell does not automatically settle those separate questions.

## A practical comparison with conventional Nix shells

The closest alternative is a conventional Nix development shell built with `pkgs.mkShell` or `pkgs.stdenv.mkDerivation`. Both approaches use Nix to obtain pinned or selected packages, and both can be entered through Nix tooling. devshell's difference is composition and presentation. It starts from `builtins.derivation`, exposes a smaller environment, adds project-oriented variables, provides a TOML path, and supports runnable commands through `nix run`.

A conventional `pkgs.mkShell` is the better fit when a project depends on the variables and setup behavior supplied by `stdenv`. It may also be easier to understand for maintainers who already rely on Nix's standard derivation helpers. devshell is the better fit when the project needs a deliberately narrow command environment and wants direnv integration or Nix application execution without entering an interactive shell.

The choice is therefore not simply devshell versus no environment management. It is devshell versus the conventional Nix shell contract. Before selecting it, compare the required variables, shell initialization scripts, compiler expectations, completion needs, and CI build steps for the target repository. The README supplies useful examples, but it does not claim universal compatibility with every existing Nix derivation.

## Conclusion

Adopt numtide/devshell when a project already uses Nix and wants a smaller, declarative development shell with TOML, direnv, or Nix configuration. Do not adopt it as a general shell manager or assume that its unstable status is appropriate for a production standard. Verify first whether the documentation and package set cover your operating system, required shells, and CI workflow, then review the exact environment variables introduced by the project.

## FAQ

### What problem does numtide/devshell solve?

It is designed to simplify per-project developer environments and help contributors obtain a project's development dependencies after cloning the repository. It supports Nix, direnv, TOML, and runnable Nix applications.

### How do I run a devshell command with numtide/devshell?

The README shows `nix run 'github:numtide/devshell' -- hello` for running the project's application. For project-defined commands, the documented form is `nix run '.#<myapp>' -- <devshell-command> <and-args>`.

### Can numtide/devshell replace pkgs.mkShell?

Not universally. devshell intentionally uses a smaller environment based on `builtins.derivation`, while `pkgs.mkShell` inherits more of Nix's standard shell environment. Projects that depend on the additional variables or behavior from `pkgs.mkShell` may be better served by the conventional option.

## Sources

- [Issues](https://github.com/numtide/devshell/issues)
- [License: MIT](https://github.com/numtide/devshell/blob/main/LICENSE)
- [numtide/devshell on GitHub](https://github.com/numtide/devshell)
- [Project website](https://numtide.github.io/devshell/)
- [README](https://github.com/numtide/devshell/blob/main/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/numtide-devshell
