This is by no means complete, please add to it and share your own!
Shallow clone nixpkgs when the full Git history isn't always necessary - this can speed up build times.
The only issue I've had is nix-index-database not working well with the shallow clone. Other than that, no issues after running for a few months.
inputs = {
nixpkgs.url = "git+https://github.com/NixOS/nixpkgs?shallow=1&ref=nixos-unstable";
};Sometimes when you might need a full clone are debugging and working with repository history, but those are rare cases.
You can import your non-flake repositories (like wallpapers) as inputs:
inputs = {
wallpapers = {
url = "git+ssh://[email protected]/TSawyer87/wallpapers.git";
flake = false;
};
}After adding the input, you can access individual wallpapers by adding the inputs argument and something like:
path = "${inputs.wallpapers}/Aesthetic Scenery.jpg";@-patterns allow you to reference your outputs argument set as a whole. An @-pattern is a way for a function to access variadic attributes (i.e., varying number of arguments).
inputs = {
home-manager.url = "github:nix-community/home-manager/master";
home-manager.inputs.nixpkgs.follows = "nixpkgs";
stylix.url = "github:danth/stylix";
};
outputs = {
self,
nixpkgs,
home-manager,
} @ inputs:With the above example, to add the modules to your nixosConfigurations you would add something like this:
nixosConfigurations.${host} = nixpkgs.lib.nixosSystem {
inherit system;
specialArgs = {
inherit inputs username host email systemSettings;
};
modules = [
./hosts/${host}/config.nix
inputs.stylix.nixosModules.stylix
home-manager.nixosModules.home-manager
# .. snip ..
];Important note: Since home-manager was explicitly listed in the outputs arguments (outputs = { self, nixpkgs, home-manager, }), the inputs prefix is unnecessary. If home-manager was removed from the outputs arguments (outputs = { self, ... }), then you would need modules = [ inputs.home-manager.nixosModules.home-manager ];
This can be confusing because many docs assume you're not using an @-pattern, so if you have one in your flake you need to prefix with inputs.
Building on @-patterns, using specialArgs (NixOS) and extraSpecialArgs (home-manager) is a way to pass arguments from your flake to your NixOS and home-manager modules.
For example, here's a snippet of some variables you might set:
outputs = {
self,
nixpkgs,
home-manager,
...
} @ inputs: let
system = "x86_64-linux";
host = "magic";
username = "jr";
userVars = {
timezone = "America/New_York";
locale = "en_US.UTF-8";
gitUsername = "TSawyer87";
dotfilesDir = "~/.dotfiles";
wm = "hyprland";
browser = "firefox";
term = "ghostty";
editor = "hx";
keyboardLayout = "us";
};
inNow you can pass them as special args like this:
nixosConfigurations = {
${host} = nixpkgs.lib.nixosSystem {
inherit system;
specialArgs = {
inherit
inputs
username
system
host
userVars
;
};
modules = [
./hosts/${host}/configuration.nix
home-manager.nixosModules.home-manager
inputs.stylix.nixosModules.stylix
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.users.${username} = import ./hosts/${host}/home.nix;
home-manager.backupFileExtension = "backup";
home-manager.extraSpecialArgs = {
inherit
inputs
username
system
host
userVars
;
};
}
];
};
};To access values in userVars, for example:
{ userVars, ... }: {
programs = {
git = {
enable = true;
userName = userVars.gitUsername;
};
};
}Add treefmt-nix to your inputs and outputs arguments. Inside the let expression from tip 4, add:
let
# ... snip ...
pkgs = import nixpkgs {
inherit system;
config.allowUnfree = true;
};
treefmtEval = treefmt-nix.lib.evalModule pkgs ./treefmt.nix;
in
{
checks.x86_64-linux.style = treefmtEval.config.build.check self;
formatter.x86_64-linux = treefmtEval.config.build.wrapper;
# ... snip ...
}And in the treefmt.nix:
{
projectRootFile = "flake.nix";
programs = {
deadnix.enable = true;
statix.enable = true;
keep-sorted.enable = true;
nixfmt = {
enable = true;
strict = true;
};
};
settings.excludes = [
"*.age"
"*.jpg"
"*.nu"
"*.png"
".jj/*"
"flake.lock"
"justfile"
];
settings.formatter = {
deadnix = {
priority = 1;
};
statix = {
priority = 2;
};
nixfmt = {
priority = 3;
};
};
}Use treefmt-nix to manage code formatters and linters as flake outputs. This ensures consistent styling and catches issues with tools like deadnix, statix, and nixfmt.
Usage:
- Use
nix fmtin the flake directory to format your whole configuration - Run
nix flake checkto run your checks - Run
nix flake showto list your outputs - Tools like
nix-fast-buildrely on flake checks and can be used after setting this up
Make a devShell output:
in
{
checks.x86_64-linux.style = treefmtEval.config.build.check self;
formatter.x86_64-linux = treefmtEval.config.build.wrapper;
devShells.${system}.default = import ./lib/dev-shell.nix { inherit inputs; };
}And in the dev-shell.nix you could put something like this:
{
inputs,
system ? "x86_64-linux",
}:
let
# Instantiate nixpkgs with the given system and allow unfree packages
pkgs = import inputs.nixpkgs {
inherit system;
config.allowUnfree = true;
overlays = [
# Add overlays if needed, e.g., inputs.neovim-nightly-overlay.overlays.default
];
};
in
pkgs.mkShell {
name = "nixos-dev";
packages = with pkgs; [
# Nix tools
nixfmt-rfc-style # Formatter
deadnix # Dead code detection
nixd # Nix language server
nil # Alternative Nix language server
nh # Nix helper
nix-diff # Compare Nix derivations
nix-tree # Visualize Nix dependencies
# Code editing
helix
# General utilities
git
ripgrep
jq
tree
];
shellHook = ''
echo "Welcome to the NixOS development shell!"
echo "System: ${system}"
echo "Tools available: nixfmt, deadnix, nixd, nil, nh, nix-diff, nix-tree, helix, git, ripgrep, jq, tree"
'';
}You can enter this development shell with nix develop or automatically with direnv.