# Why you should flox every day

I want to share a very valuable tool that I have been using for almost a year now: `flox`.

# How I avoided nix for so long

I never had a strong desire to completely control the software running on my machine. I was more focused on setting up an environment quickly and then dedicating all my time to developing software. However, this approach came at a cost. Every time I switched companies, I had to set up a brand-new computer and reinstall all my software. Typically, this meant a few days of frustration, but it also allowed me to clear out all the accumulated clutter from my previous job.

I was envious though of those people who were re-installing their computer in a matter of minutes, dot files, system libraries, development environments, etc...

Some of them had a secret trick for this: [Nix](https://nixos.org/).

Nix should have been appealing to me as a functional programmer, given its features like immutable deployments, isolation, easy rollbacks, and more. However, Nix had a reputation for being difficult to understand, challenging to use, and constantly evolving.

Ian Henry's "[How to Learn Nix](https://ianthehenry.com/posts/how-to-learn-nix/)" is an excellent rendition of some of those difficulties. I could *feel in my bones* the kind of rabbit hole that learning Nix would be. Is it worth the loss of a few days every few years?

If I'm being honest, it was more than that. In my previous job, we had a mixture of technologies: Haskell, Go, Python, Postgres, etc. Even using some cryptographic libraries in Python meant building Rust code! As a result, my development environment started breaking much more frequently. Every month or so, some system library would be missing, `python` wouldn't be the right version anymore, and my `PATH` would become a mess. Nix was becoming increasingly compelling...

# It doesn't have to be hard

With `flox` I can create several environments:

* `dotfiles` for my `zsh` configuration
    
* `default` for my common day-to-day tools
    
* `scala` for my open-source Scala projects
    
* `haskell` for my open-source Haskell projects
    
* `rust` for my open-source Rust projects
    
* `ockam` for my project at work
    

My `.zshrc` configuration file now is simply:

```bash
eval "$(flox activate -e flox/default)"
eval "$(flox activate -e dotfiles)"
```

This starts the `flox/default` environment giving me access to the latest version of `flox`, then my `dotfiles` environment.

The `activate` command:

* grabs the packages defined in the environment from a nix packages repository, builds them, and caches them locally (so that it is only slow the first time)
    
* puts the binaries included in those packages on the `PATH`
    

# Dot files

What is in my `dotfiles` environment? We can have a look at it with the `edit` command:

```bash
> flox edit -e dotfiles
{
  shell.hook = ''
    export ZDOTDIR=$HOME/.dotfiles
    exec zsh --no-globalrcs
  '';
  packages.nixpkgs-flox.zsh = {};
  packages.nixpkgs-flox.starship = {};
}
```

The `dotfiles` environment exports the `ZDOTDIR` variable and starts `zsh`.

The `ZDOTDIR` variable points to `$HOME/.dotfiles` directory, which is versioned with Github. That directory contains all the files used in my `.zsh` configuration.

I am also fetching the fabulous [`starship` prompt](https://starship.rs/), which, with a bit of configuration, allows me to display the currently activated `flox` environments

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1694947952890/b15f400e-54d3-41d5-85f4-8445ecba7343.png align="center")

I now have:

* versioned dot files,
    
* which can be easily reinstalled if I use a new computer
    

# The many tools of the trade

Wait! Where does the additional `default` environment come from? This environment is activated by the `$HOME/.dotfiles/.zshrc` configuration file. It contains all the tools I rely on to be effective at my job. For example the ultra-fast versions of `grep` and `find` (`rg` and `fd`, implemented in Rust).

`flox list -e default` provides the whole list:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1694948415321/912ff515-e705-4581-ae0e-eb130e066541.png align="center")

Several things to mention about this list:

* this is the 101st generation! I have frequently modified this list. `flox` can actually list all the modifications since it was created. I can also revert to any previous version if I want to
    
* all the usual suspects can be found in that list: `git`, `rg`, `tree`, etc... There is a very high chance that if you need an executable, you will find it by searching [the nix packages](https://search.nixos.org/packages)
    
* some packages come from my own repositories. I published what was missing, using, ... `flox`
    

# Publishing the rest

For example, the excellent [`cmt` tool](https://github.com/smallhadroncollider/cmt) allows you to use a template to format your commit messages (respecting the [conventionalcommits standard](https://www.conventionalcommits.org/en/v1.0.0/) if you want to)

![Demo](https://github.com/smallhadroncollider/cmt/raw/master/docs/cmt-0.7.gif align="left")

This is a tool that I use every day but it does not exist as a `nix` package. So I published it myself!

I forked the original repository and ran `flox init` to make it a flox project:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1694949284391/a680b81b-5974-4ca7-bc7c-db24735026f9.png align="left")

There is no pre-packaged project template for Haskell (which is how `cmt` is implemented), so I used `package-simple`.

This is where I had to learn more about Nix, so I could understand how to build the project. `cmt` is a small Haskell project so building it is not particularly involved

```bash
❯ cat pkgs/commit-tool/default.nix                                                                                                                                                                                                                                    dotfiles flox/default default
{ self, pkgs, stdenv, lib, haskellPackages }:
with haskellPackages;
  mkDerivation rec {
    pname = "cmt";
    version = "0.7.1.1";
    src = ../../.;
    isExecutable = true;
    libraryHaskellDepends = [
      ansi-terminal attoparsec base classy-prelude containers directory
      file-embed filepath process terminal-size text
    ];
    executableHaskellDepends = [ base classy-prelude ];

    doHaddock = false;
    doCheck = false;

    homepage = "https://github.com/smallhadroncollider/cmt#readme";
    description = "Write consistent git commit messages";
    license = lib.licenses.bsd3.spdxId;
    mainProgram = "cmt";
  }
```

The definition above declares that:

* we want to make an executable named `cmt`
    
* sources can be found at `../../.`
    
* the package depends on other Haskell libraries
    

The next step is to use `flox publish` to make the package available to everyone. My teammates can subscribe to the repository containing the package and install it in their environment.

But they don't even have to do that!

# Sharing is caring

One great benefit of creating a `flox` environment is the ability to save it to a Github repository with the `flox push` command.

This is useful for yourself because, the day you switch to another laptop, you can simply download the environment again with `flox pull` and be ready in minutes.

This is also particularly useful for teams working on the same project because you can make sure that everyone is always working with the same version of the same tools: `postgres`, `python`, `jq`, etc... thus reducing the risk of "But it works on my machine!".

Another significant benefit of using environments is **their complete isolation**. Activating an environment only adds the executables for that specific environment to the `PATH`. When you exit the environment, everything is removed. You have complete control over what is in scope.

**Note**: I have been using `flox` mostly as a package manager to handle "[managed environments](https://flox.dev/docs/tutorials/managed-environments/)". There is also a concept of "[project environments](https://flox.dev/docs/tutorials/projects/)" where the `flox` configuration contains everything: how to build, test, release. The command used to enter a project environment is just `flox develop` in the project directory.

# Less typing

One last tip. Having to type `flox activate -e scala` every time you want to work on a Scala project can become pretty tiresome. The solution to this problem is to use [`direnv`](https://direnv.net/). With `direnv` you add a `.envrc` file to your project directory:

```bash
eval "$(flox activate -e scala)"
```

Every time you `cd` into the project directory, `direnv` runs the `.envrc` file and that activates the right environment. Neat!

# Getting some help

I encourage you to explore Flox and see how it can assist you in managing all your environments effortlessly. However, when you venture into building and publishing packages you might have to better understand `flox`'s notion of catalog/channels and know your way around `nix`. Don't hesitate to leave a message on the [flox Discourse site](https://discourse.flox.dev/), the team is very responsive and friendly!
