Migrating from Homebrew to Nix and Nix-Flakes on the M1
My first steps with Nix on Mac OSX as Homebrew replacement
I finally had some time to play around with Nix - the immutable package manager and build system.  This was on my agenda since a long time, but I finally took the plunge on my M1 OSX system. I by no means understand Nix fully yet, but making progress and it is usable to me already.Getting StartedI started by reading all of zero-to-nix.com - a great website which explains the first baby steps. For installing, I used the unofficial installer DeterminateSystems/nix-installer for reasons explained on the website, which ran through smoothly.After doing the tutorials at zero-to-nix.com, I wondered how to continue. After all, I had two main goals:have a reproducible global dev tool setup (basically a replacement for Homebrew)have reproducible dev environments (basically replacing docker)For the second use case, reproducible dev environments, I quickly settled on cachix/devenv. I also checked out jetpack-io/devbox which does fundamentally the same thing; but which hides the Nix files completely underneath - so that was too restrictive for my tastes.When reading about the ecosystem, I saw there are lots of patterns how one could use Nix; and this is in flux right now, as the community irons out flakes (which many people seem to be using already though). So I for now decided on the following:Embrace Nix Flakes: I'll only use nix flakes, especially after reading this blog post.Only use the nix tool, instead of the older nix-env etc tools. It seems the new world and the old world sometimes are incompatible, and you need to decide which way to go consistently.Only go declarative: I will never install a package by typing a CLI command, but always editing some configfile and running a "converge" script.I have read that flakes and nix are still considered alpha; but from my perspective right now it feels 95% done - and maybe other projects would have called this a finished product by now. So I feel good about using this.Global Dev SetupFor installing tools globally, I've read about nix profiles, but I was unsure about how to use them with Flakes. I then stumbled over this forum post, which is the way I am doing it now:I created a folder in ~/nix-sebastian (does not matter) containing my global Nix configuration.In this folder, I placed a flake.nix (content see below), effectively making this folder a flake.Then, for initial installation, I ran nix profile install . (inside the folder). This registered the flake.nix as part of the global nix profile. You can see that nix profile list shows the profile. To update, you need to run nix profile upgrade 0 (assuming you only have this single profile installed) - if you have multiple profiles installed, you need to use the number displayed at the front of the listing.Pitfall: you are not allowed to re-run nix profile install ., as this will install the profile a second time - and this will lead to conflicts. This is what I stumbled over at first :)flake.nix skeletonThe following is the skeleton file I am using for global installation. To understand the syntax, this post about language basics and this post about functions have been helpful for me.# flake.nix skeleton:

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs";
  };

  outputs = { self, nixpkgs }: {
    packages."aarch64-darwin".default = let
      pkgs = nixpkgs.legacyPackages."aarch64-darwin";
    in pkgs.buildEnv {
      name = "home-packages";
      paths = with pkgs; [

        # general tools
        git

		# ... add your tools here
      ];
    };
  };

}Development Environments with devenvI cannot say much about devenv.sh, except that it works as intended :) The docs are a bit sparse, but I found the devenv.nix file reference to be extremely helpful. It shows what you can all install and how you can customize the environment - I especially like the customizability of languages, and that the system supports services and scripts. As an example, for a Neos/Flow PHP application, I am using the following devenv.nix. It does not yet install all optimal PHP extensions, but it already sets up a database with permissions :)In case you wonder, I used the "Advanced (declaratively with flakes)" installation method of devenv.sh described here.# devenv.nix

{ pkgs, ... }:

{
  languages.php.enable = true;
  languages.php.package = pkgs.php82;

  services.mysql = {
    enable = true;
    initialDatabases = [
      { name = "neos"; }
    ];
    ensureUsers = [
      {
        name = "neos";
        ensurePermissions = {
          "neos.*" = "ALL PRIVILEGES";
        };
      }
    ];
  };

  starship.enable = true;
}Bonus and Closing ThoughtsSo far I like what I saw :) I only played around with this for a few hours, but I was already able to remove most of my homebrew packages and convert them to Nix. I am curious where I will end up :)In case you are interested, below is my current global flake.nix file, with the following specials:install devenvinstall diverse language toolchains (Rust, php, deno, node, JDK, go)install PHP with extensionscustom-compile a PHP extensionmy current global flake.nix file# global flake.nix
{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs";
    unstable.url = "nixpkgs/nixos-unstable";
    devenv.url = "github:cachix/devenv/latest";

    # rust, see https://github.com/nix-community/fenix#usage
    fenix = {
      url = "github:nix-community/fenix";
      inputs.nixpkgs.follows = "unstable";
    };
  };

  outputs = { self, nixpkgs, unstable, devenv, fenix }: {
    packages."aarch64-darwin".default = let
      pkgs = nixpkgs.legacyPackages."aarch64-darwin";
      unstablePkgs = unstable.legacyPackages."aarch64-darwin";
      
      # see https://github.com/Mic92/nixos-wiki-test/blob/196aa6c3463bf52128d3ffb07218d0999b2ca617/PHP.md?plain=1#L38
      php-vips = pkgs.php81.buildPecl {
        pname = "vips";
        version = "1.0.13";
        sha256 = "TmVYQ+XugVDJJ8EIU9+g0qO5JLwkU+2PteWiqQ5ob48=";
        buildInputs = [ pkgs.vips pkgs.pkg-config ];
      };
      php81 = pkgs.php81.buildEnv {
        extensions = ({ enabled, all }: enabled ++ (with all; [
            xdebug
            opcache
            redis
            php-vips
        ]));
        extraConfig = "memory_limit = 2G";
      };
    in pkgs.buildEnv {
      name = "home-packages";
      paths = with pkgs; [

        # general tools
        git
        bitwarden-cli
        ffmpeg
        gnupg
        curl
        wget
        jq
        gnused
        ripgrep
        tmux
        pandoc

        # dev tools
        devenv.packages.aarch64-darwin.devenv
        mitmproxy
        cfssl
        dive
        graphviz
        lnav # log file nav
        watchman
        vector
        kubectl
        httpie
        certstrap
        lima
        caddy
        mutagen
        mutagen-compose
        upx
        age
        dbmate
        gomplate
        jwt-cli
        ipcalc
        ncdu
        inetutils # telnet

        # infrastructure
        ansible
        k3d
        k9s
        natscli
        nats-server
        redis
        trivy


        # programming environments
        deno
        nodejs
        yarn
        php81
        symfony-cli
        fenix.packages."aarch64-darwin".minimal.toolchain # rust
        jdk17
        
        # go
        go
        unstablePkgs.goreleaser
        protobuf # TODO remove
        protoc-gen-go # TODO remove
        protoc-gen-go-grpc # TODO remove
        golangci-lint # TODO remove
        buf # TODO remove
        gum # TODO REMOVE


        #mariadb
        #postgresql
        
        
        # to remove
        awscli
        google-cloud-sdk
        platformio
        arduino-cli
        openfortivpn
        hcloud

        pgcli
    
        # mobile dev
        # TODO Flutter does not work
        cocoapods
        fastlane
        
      ];
    };
  };

}