Profiles
Profiles allow you to organize different variations of your development environment. You can activate profiles manually using CLI flags or have them activate automatically based on your system environment.
Basics
Define profiles in your devenv.nix
file using the profiles
option:
{ pkgs, config, ... }: {
profiles = {
backend.module = {
services.postgres.enable = true;
services.redis.enable = true;
env.ENVIRONMENT = "backend";
};
frontend.module = {
languages.javascript.enable = true;
processes.dev-server.exec = "npm run dev";
env.ENVIRONMENT = "frontend";
};
testing.module = { pkgs, ... }: {
packages = [ pkgs.playwright pkgs.cypress ];
env.NODE_ENV = "test";
};
};
}
Use the --profile
flag to activate one or more profiles:
# Activate a single profile
$ devenv --profile backend shell
# Activate multiple profiles
$ devenv --profile backend --profile testing shell
When multiple profiles are active, devenv wraps every profile module in a deterministic priority. Conflicting options are resolved by those priorities instead of relying on evaluation order.
Profile priorities
Profile priorities are assigned automatically so you can reason about overrides:
- Base configuration always loads first and has the lowest precedence.
- Hostname profiles activate next, followed by user profiles.
- Manual profiles passed with
--profile
have the highest precedence; if you pass several profiles, the last flag wins. - Extends chains resolve parents before children, so child profiles override their parents without extra
mkForce
calls.
This ordering keeps large profile stacks predictable even when several profiles change the same option.
Here is a simple example where every tier toggles the same option, yet the final value stays deterministic:
{ config, ... }: {
myteam.services.database.enable = false;
profiles = {
hostname."dev-server".module = {
myteam.services.database.enable = true;
};
user."alice".module = {
myteam.services.database.enable = false;
};
qa.module = {
myteam.services.database.enable = true;
};
};
}
When Alice runs on dev-server
, the hostname profile enables the database, her user profile disables it again, and a manual devenv --profile qa shell
flips it back on. Conflicts resolve in priority order without any extra override helpers.
Merging profiles
Profiles can extend other profiles using the extends
option, allowing you to build hierarchical configurations and reduce duplication:
{
name = "myproject";
packages = [ pkgs.git pkgs.curl ];
languages.nix.enable = true;
profiles = {
backend = {
module = {
services.postgres.enable = true;
services.redis.enable = true;
};
};
frontend = {
module = {
languages.javascript.enable = true;
processes.dev-server.exec = "npm run dev";
};
};
fullstack = {
extends = [ "backend" "frontend" ];
};
};
}
Hostname Profiles
Profiles can automatically activate based on your machine's hostname:
{
profiles = {
work-tools.module = {
packages = [ pkgs.docker pkgs.kubectl pkgs.slack ];
};
hostname = {
"work-laptop" = {
extends = [ "work-tools" ];
module = {
env.WORK_ENV = "true";
services.postgres.enable = true;
};
};
"home-desktop".module = {
env.PERSONAL_DEV = "true";
};
};
};
}
User Profiles
Profiles can automatically activate based on your username:
{
profiles = {
developer-base.module = {
packages = [ pkgs.git pkgs.gh pkgs.jq ];
git.enable = true;
};
user = {
"alice" = {
extends = [ "developer-base" ];
module = {
env.USER_ROLE = "backend-developer";
languages.python.enable = true;
};
};
"bob" = {
extends = [ "developer-base" ];
module = {
env.USER_ROLE = "systems-engineer";
languages.go.enable = true;
languages.rust.enable = true;
};
};
};
};
}
Composition
All matching profiles are automatically merged when you run devenv commands:
{
languages.nix.enable = true;
profiles = {
backend.module = {
services.postgres.enable = true;
};
hostname."ci-server".module = {
env.CI = "true";
packages = [ pkgs.buildkit ];
};
user."developer".module = {
git.enable = true;
packages = [ pkgs.gh ];
};
};
}
When you run devenv --profile backend shell
on a machine named "ci-server" with user "developer", all matching profiles activate:
- Base configuration (always active)
profiles.backend
(via--profile
)profiles.hostname."ci-server"
(automatic hostname match)profiles.user."developer"
(automatic user match)