A portable, non-invasive Nix-based user environment that:
- Works inside a devcontainer you do not control
- Is installable as a devcontainer Feature
- Uses devenv + home-manager
- Also works on your local Linux host
- Does not mutate or “take over” the host system
CRITICAL NOTE: You must never use home-manager switch or system-wide Nix activation
Instead:
- use nix in signle-user mode
- use devenv for shell activation
- treat home-manager as a library, not a login manager
- keep all state under a project owned directory
Key design:
- devenv owns the shell
- home-manager only defines files/env inside that shell
layout
repo/
├── devenv.nix
├── devenv.yaml
├── home/
│ └── home.nix
├── nix/
│ └── flake.nix
└── .devcontainer/
└── devcontainer.json
use devenv as the only activation mechanism
devenv.nix is the entry point both locally and in the devcontainer
{ pkgs, lib, config, ... }:
{
packages = with pkgs; [
git
nodejs
ripgrep
];
env = {
# Redirect HOME to a project-local directory
HOME = "${config.devenv.root}/.home";
};
scripts.activate.exec = ''
mkdir -p "$HOME"
'';
}
This alone prevents host pollution.
embed home-manager inside devenv
- do not install home-manager globally
- import it as a module
{
imports = [
(builtins.fetchTarball {
url = "https://github.com/nix-community/home-manager/archive/release-23.11.tar.gz";
})
];
home-manager.users.dev = {
home.stateVersion = "23.11";
programs.git.enable = true;
home.file.".config/mytool/config.toml".text = ''
foo = "bar"
'';
};
}
devenv.nix
{
config.home-manager.useGlobalPkgs = true;
config.home-manager.useUserPackages = true;
}
NOTE: never activating HM globally — it only materializes files under $HOME, which you already sandboxed
- Make it work in an uncontrolled devcontainer, Use a Devcontainer Feature
features/nix-devenv/
├── devcontainer-feature.json
└── install.sh
#!/usr/bin/env sh
# install.sh
set -e
if ! command -v nix >/dev/null; then
curl -L https://nixos.org/nix/install | sh -s -- --no-daemon
fi
. "$HOME/.nix-profile/etc/profile.d/nix.sh"
nix profile install nixpkgs#devenv
{
"id": "nix-devenv",
"version": "1.0.0",
"name": "Nix + devenv",
"installsAfter": ["ghcr.io/devcontainers/features/common-utils"]
}
- Installs Nix per-user
- Avoids daemon mode
- Works without root
devcontainer
{
"features": {
"yourorg/nix-devenv": {}
},
"postCreateCommand": "devenv shell"
}
local linux
curl -L https://nixos.org/nix/install | sh -- --no-daemon
nix profile install nixpkgs#devenv
cd repo
devenv shell
DO NOT
- NEVER RUN home-manager switch
- NEVER programs.bash.enable = true
- DO NOT write to ~/.profile or ~/.bashrc
- NO nix-env
- NO systemd services
Hardening
env = {
XDG_CONFIG_HOME = "$HOME/.config";
XDG_DATA_HOME = "$HOME/.local/share";
XDG_CACHE_HOME = "$HOME/.cache";
};
summary: Use devenv as the shell boundary, sandbox HOME, and treat home-manager as a file generator — not a system manager