Image for post fh-updates
Sep 20, 2023 by Luc Perkins

Creating and modifying flakes using the FlakeHub CLI

Last month we at Determinate Systems announced the initial release of FlakeHub, a brand new platform for publishing and exploring Nix flakes, with features like SemVer for flakes and robust search.

Soon thereafter, we released fh, a CLI tool for interacting with FlakeHub. The initial release of fh offered a modest set of capabilities, including the ability to list and search all publicly listed flakes. But recently we’ve been iterating on the tool in earnest and today we’d like to announce two new features: fh add and fh init, both of which substantially improve the ergonomics of working with flake.nix files.

Try out fh right now:

Terminal window
nix run ""

See the README instructions to install it on your system.

fh add

The fh add command enables you to quickly add new flake inputs to an existing flake. This command, for example, would add Nixpkgs to your flake.nix:

Terminal window
fh add NixOS/nixpkgs

If you specify a flake reference as :org/:project, as in this example, fh infers that you mean a FlakeHub reference and searches to ensure the flake exists. It then adds a reference to the latest version of the flake. The resulting inputs block may look something like this (notice the FlakeHub address and the specific version):

inputs = {
nixpkgs.url = "";
# Other inputs

You can also use fh add to add non-FlakeHub references:

Terminal window
fh add github:DeterminateSystems/nuenv

fh init

Though it’s nice to have a convenient way to update flakes that already work, creating new flakes from scratch can be a bit of a chore. I’ve done it enough times that it’s now ingrained in my muscle memory but I don’t look forward to it and we at Determinate Systems suspect that no one does. So we added an fh init command to the FlakeHub CLI. All you have to do is run it in the root of a project and 🪄🦄🧚‍♀️ magical things happen 🪄🦄🧚‍♀️:

Terminal window
cd /path/to/your/project
fh init

fh init assumes that you don’t yet have a flake.nix at the root of your project (and if you do, it only overwrites it if you explicitly opt for that). Then it looks at the contents of your project and asks you a series of questions about what you want. At the end of that process, it outputs a flake.nix file that you can immediately use in your project. That’s it!

Try it in a flake-less project now:

Terminal window
nix run "" -- init

Here’s an example fh init flow:

  • If your project has a Cargo.toml file, it asks if this is indeed a Rust project.
  • If you say yes, then it checks for a rust-toolchain or rust-toolchain.toml file.
  • If one is present, it uses that to create your Rust environment; if not, it uses the latest stable version of Rust.

Similar flows are currently available for Go, Java, JavaScript, PHP, Python, Ruby, and Zig. Beyond these language-specific helpers, fh init also enables you to:

  • Provide a description of the flake
  • Include helpful doc comments explaining various aspects of the flake
  • Include common utilities like curl, jq, Git, and nixpkgs-fmt (the Nix formatter that we prefer at Determinate Systems)
  • Generate a flake-friendly direnv configuration file
  • Select which systems you want the flake to support (x86_64-linux, aarch64-darwin, etc.)
  • Provide custom environment variables

As we usually do at DeterminateSystems, we have strong—though hopefully informed—opinions about how things should be, and flakes are, unsurprisingly, no exception to that. Some opinions that we baked into fh init:

  • Rather than using libraries like flake-utils or flake-parts, it generates plain old Nix functions as helpers for generating per-system outputs.
  • It always adds Nixpkgs as an input, as it’s necessary for pretty much all the flakes that fh init generates. It does, however, enable you to select which version of Nixpkgs you want.

But fh init is just a starter. You’re always free to customize at will; after all, it’s just Nix code!

We should also note here that fh init is different from flake templates and the related nix flake init command. Flake templates essentially copy pre-existing files—including flake.nix files if you want—into your current directory (or a new directory). fh init, conversely, takes the specifics of your project and your desires into account.

More on the way for fh

We’re confident that fh add and fh init will polish off some of the rough edges of working with flakes. But we have plans to improve fh init pretty dramatically in the near future, including:

  • Support for generating flake outputs beyond devShells, such as package outputs
  • More language- and tool-specific interactive flows

In the meantime, please don’t hesitate to provide feedback in the form of issues and pull requests. Or join us on Discord if you just want to chat about FlakeHub.

Avatar for Luc Perkins
Written by Luc Perkins

Luc is a technical writer, software engineer, and Nix advocate who's always on the lookout for qualitatively better ways of building software. He originally hails from the Pacific Northwest but has recently taken to living abroad.