devshell does not include `outputs` attrs
Describe the bug
A vanilla flake (or even with flake-parts) with devShells entry will yield, for example, a outputs.devShells.aarch64-darwin.default.outputs attribute set.
A flake using on devshell does not have this attribute set.
To Reproduce
Steps to reproduce the behavior:
Vanilla/flake-parts flake:
{
description = "Description for the project";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-parts = {
inputs.nixpkgs-lib.follows = "nixpkgs";
url = "github:hercules-ci/flake-parts";
};
};
outputs =
inputs@{ flake-parts, ... }:
flake-parts.lib.mkFlake { inherit inputs; } {
systems = [
"aarch64-darwin"
];
perSystem =
{
pkgs,
...
}:
{
devShells.default = pkgs.mkShell {
packages = [
pkgs.git
];
};
};
};
}
in nix repl, this yields:
nix-repl> outputs.devShells.aarch64-darwin.default.outputs
[ "out" ]
Using a minimal devshell flake:
{
description = "Description for the project";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-parts = {
inputs.nixpkgs-lib.follows = "nixpkgs";
url = "github:hercules-ci/flake-parts";
};
devshell.url = "github:numtide/devshell";
};
outputs =
inputs@{ flake-parts, ... }:
flake-parts.lib.mkFlake { inherit inputs; } {
imports = [ inputs.devshell.flakeModule ];
systems = [
"aarch64-darwin"
];
perSystem =
{
pkgs,
...
}:
{
devshells.default = {
packages = [
pkgs.git
];
};
};
};
}
nix repl yields:
nix-repl> outputs.devShells.aarch64-darwin.default.outputs
warning: Nix search path entry '/Users/max/.nix-defexpr/channels' does not exist, ignoring
error: attribute 'outputs' missing
at «string»:1:1:
1| outputs.devShells.aarch64-darwin.default.outputs
| ^
Expected behavior
I am interpreting derivation {}'s docs to imply that while it's outputs argument is optional, because it has a default "out", all flake outputs can be expected to have a *.default.outputs attribute set.
System information
This is macOS 15.3.1, nix (Nix) 2.26.2.
Additional context
Other software such as flake-iter also seems to assume the *.default.outputs attribute; that's where I ran into this problem, see https://github.com/DeterminateSystems/flake-iter/issues/22
hey You've correctly identified a difference in the structure of the devShell attribute set when using pkgs.mkShell directly (via vanilla flakes or flake-parts without devshell) versus using the numtide/devshell flake module.
Explanation of the Difference
-
Vanilla
pkgs.mkShell/flake-parts:- When you define
devShells.default = pkgs.mkShell { ... };, you are directly assigning the result ofpkgs.mkShellto thedefaultattribute within your flake's outputs (outputs.devShells.<system>.default). -
pkgs.mkShellfundamentally creates a Nix derivation. - According to Nix documentation and standard behavior, derivations have certain standard attributes. One of these is
outputs, which is a list of strings representing the names of the derivation's outputs. - By default, most derivations (including those from
mkShell) have a single output named"out". - Therefore, the derivation created by
pkgs.mkShellhas an attributeoutputswith the value[ "out" ]. This is what you observe in your first example.
- When you define
-
numtide/devshellFlake Module:- When you use
imports = [ inputs.devshell.flakeModule ];and defineperSystem.devshells.default = { ... };(note the pluraldevshellsused by the module), you are not directly callingpkgs.mkShellyourself in the final output structure. - Instead, the
devshell.flakeModuletakes your configuration (underperSystem.devshells) and uses its own internal logic (likely involvingdevshell.lib.mkShellor similar functions which eventually callpkgs.mkShellorpkgs.stdenv.mkDerivation) to construct the final attributes underoutputs.devShells.<system>. - The
numtide/devshelllibrary adds its own features and abstractions (like commands, environment variables management, hooks, etc.). The final attribute set it places atoutputs.devShells.<system>.defaultis not necessarily the raw derivation itself. It's a structure defined bynumtide/devshellwhich contains the information needed fornix developornix shellto work correctly with thedevshellfeatures. - Because the structure at
outputs.devShells.<system>.defaultisn't the raw derivation, it doesn't necessarily expose the derivation's standardoutputsattribute directly at that level. The actual derivation might be nested within this structure, ordevshellmight construct it in a way that omits or places the.outputsattribute elsewhere (or nowhere accessible at that top level).
- When you use
Addressing Your Expectation
Your interpretation of the derivation {} documentation is correct for standard Nix derivations. However, flake outputs can contain any valid Nix attribute set, not just raw derivations.
The numtide/devshell library provides an abstraction over pkgs.mkShell. The structure it outputs under outputs.devShells.<system>.default is specific to how devshell works and is designed to be consumed by nix develop in conjunction with devshell's tooling. It doesn't guarantee to expose all the raw attributes of the underlying derivation (like .outputs) at that specific path.
Conclusion
This isn't strictly a "bug" in numtide/devshell in the sense of it malfunctioning, but rather a consequence of the abstraction it provides. It constructs the devShell output differently than a direct pkgs.mkShell call.
-
Vanilla/flake-parts:
outputs.devShells.<system>.defaultis the derivation -> has.outputsattribute. -
numtide/devshell:
outputs.devShells.<system>.defaultis a structure generated by the devshell module (which internally uses a derivation) -> does not necessarily expose the underlying derivation's.outputsattribute at this top level.
The incompatibility you observed with flake-iter arises because flake-iter assumes the common pattern where devShells.<system>.default is a derivation and thus expects the .outputs attribute, which isn't true when using the numtide/devshell abstraction.