Introduction

Nixflk is a template which grants a simple way to use, deploy and manage NixOS systems for personal and productive use. It does this by providing a sane repository structure, integrating several popular projects like home-manager, setting clear guidelines, offering useful conveniences, and eliminating boilerplate so you can focus on deploying your systems.

Community Profiles

There are two branches from which to choose: core and community. The commuity branch builds on core and includes several ready-made profiles for discretionary employment.

⚠ Advisory

Nixflk leverages the flakes feature available via an experimental branch of nix. Until nix 3.0 is released, this project should be considered unstable.

License

Nixflk is licensed under the MIT License.

Quick Start

The only dependency is nix, so make sure you have it installed.

Get the Template

Here is a snippet that will work as long as nix-shell is in your path:

nix-shell https://github.com/nrdxp/nixflk/archive/core.tar.gz -A shell \
  --run "flk get core"

cd flk

nix-shell

git init
git add .
git commit -m init

You can change core to community in the call to flk get

This will place you in a new folder named flk in the current directory with git set up, and a nix-shell that provides all the dependencies, including the required nix version.

Next Steps:

ISO

Making and writing an installable iso for hosts/NixOS.nix is as simple as:

flk iso NixOS

dd bs=4M if=result/iso/*.iso of=/dev/$your_installation_device \
  status=progress oflag=sync

This works for any file matching hosts/*.nix excluding default.nix.

From NixOS

Generate Configuration

Assuming your happy with your existing partition layout, you can generate a basic NixOS configuration for your system using:

flk up

This will make a new file hosts/up-$(hostname).nix, which you can edit to your liking.

While the up sub-command is provided as a convenience to quickly set up and install a "fresh" NixOS system on current hardware, committing these files is discouraged.

They are placed in the git staging area automatically because they would be invisible to the flake otherwise, but it is best to move what you need from them directly into a host module of your own making, and commit that instead.

Make sure your i18n.defaultLocale and time.timeZone are set properly for your region. Keep in mind that networking.hostName with be automatically set to the filename of your hosts file, so hosts/my-host.nix will have the hostname my-host.

Now might be a good time to read the docs on suites and profiles and add or create any that you need.

Installation

Once your ready to deploy hosts/my-host.nix:

flk my-host switch

Instead of switch, you can pass build, test, boot, etc just as with nixos-rebuild.

This calls nixos-rebuild with sudo to build and install your configuration.

It is convenient to have the template living at /etc/nixos so you can simply sudo nixos-rebuild switch from anywhere on the system, but it is not required.

Layout

This section describes the layout of nixflk and the purpose of each subdirectory.

Hosts

Nix flakes contain an output called nixosConfigurations declaring an attribute set of valid NixOS systems. To simplify the management and creation of these hosts, nixflk automatically imports every *.nix file inside this directory to the mentioned attribute set, applying the projects defaults to each. The only hard requirement is that the file contain a valid NixOS module.

As an example, a file hosts/system.nix will be available via the flake output nixosConfigurations.system. You can have as many hosts as you want and all of them will be automatically imported based on their name.

For each host, the configuration automatically sets the networking.hostName attribute to the name of the file minus the .nix extension. This is for convenience, since nixos-rebuild automatically searches for a configuration matching the current systems hostname if one is not specified explicitly.

It is recommended that the host modules only contain configuration information specific to a particular piece of hardware. Anything reusable across machines is best saved for profile modules.

This is a good place to import sets of profiles, called suites, that you intend to use on your machine.

Additionally, this is the perfect place to import anything you might need from the nixos-hardware repository.

Example

hosts/librem.nix:

{ suites, hardware, ... }:
{
  imports = suites.laptop ++ [ hardware.purism-librem-13v3 ];

  boot.loader.systemd-boot.enable = true;
  boot.loader.efi.canTouchEfiVariables = true;

  fileSystems."/" = { device = "/dev/disk/by-label/nixos"; };
}

Profiles

Profiles are simply NixOS modules which contain generic expressions suitable for any host. A good example is the configuration for a text editor, or window manager. If you need some concrete examples, just checkout the community branch.

Constaints

For the sake of consistency, there are a few minor constraints. First of all, a profile should always be defined in a default.nix, and it should always be a a function taking a single attribute set as an argument, and returning a NixOS module which does not define any new module options. If you need to make new module option declarations, just use modules.

These restrictions help simplify the import logic used to pass profles to suites.

Example

profiles/develop/default.nix:

# good profile definition
{ lib, ... }:
{
  # profile definitions
}

profiles/develop.nix:

# bad profile definition
{
  options = {};
  # module definitions
}

Subprofiles

Profiles can also define subprofiles. They follow the same constraints outlined above. A good top level profile should be a high level concern, such a your personal development environment, and the subprofiles should be more concrete program configurations such as your text editor, and shell configs. This way, you can either pull in the whole development profile, or pick and choose individual programs.

Conclusion

Profiles are the most important concept in nixflk. They allow us to keep our nix expressions self contained and modular. This way we can maximize reuse while minimizing boilerplate. Always strive to keep your profiles as generic and modular as possible. Anything machine specific belongs in your host files.