Add input to flake.nix:

impermanence.url = "github:nix-community/impermanence";
flake.nix:inputs

Add the module to modules list of nixosSystem calls:

inputs.impermanence.nixosModules.impermanence
nixos

By default impermanence can be configured with a configuration like this:

{
  environment.persistence."/persist" = {
    enable = true;
    hideMounts = true;
    directories = [
      "/var/lib/nixos"
      "/var/lib/systemd/coredump"
      "/var/log"
    ];
  };
}

I however don’t want to have a simpler config. So using this:

{ lib, config, ... }:
 
let
  inherit (lib) mkOption types;
  cfg = config._.persist;
in
{
  options._.persist = {
    root = mkOption {
      type = types.str;
      default = "/persist";
    };
    directories = mkOption {
      type = with types; listOf anything;
      default = [ ];
    };
    files = mkOption {
      type = with types; listOf anything;
      default = [ ];
    };
  };
  config = {
    environment.persistence.${cfg.root} = {
      enable = true;
      hideMounts = true;
      inherit (cfg) directories files;
    };
  };
}
nixos

I can simplify the above configuration to this:

{
  _.persist.directories = [
    "/var/lib/nixos"
    "/var/lib/systemd/coredump"
    "/var/log"
  ];
}
nixos

Also, we need to set neededForBoot = true for affected file systems. We can use the apply parameter of mkOption for that:

{ lib, config, ... }:
 
let
  inherit (lib) hasPrefix mkOption types;
  inherit (config._.persist) root;
in
{
  options.fileSystems = mkOption {
    type =
      with types;
      attrsOf (
        submodule (
          { config, ... }:
          {
            options.neededForBoot = mkOption {
              apply = orig: orig || config.mountPoint == root || hasPrefix "${root}/" config.mountPoint;
            };
          }
        )
      );
  };
}
nixos

We need to ensure, that the hosts persistent dierctory is mounted when we are building a VM variant

{ config, pkgs, ... }:
 
{
  virtualisation.vmVariant = {
    virtualisation.sharedDirectories.persist = {
      source = config._.persist.root;
      target = config._.persist.root;
    };
  };
  virtualisation.vmVariantWithBootLoader.virtualisation = {
    inherit (config.virtualisation.vmVariant.virtualisation) sharedDirectories;
  };
}
nixos

Make configuring user-specific persistent directories easier as well:

{ lib, config, ... }:
 
let
  inherit (lib) mkOption types;
  cfg = config._.persist;
  allUsersPersistModule =
    with types;
    submodule (
      { name, config, ... }:
      {
        options = {
          directories = mkOption {
            type = listOf str;
            default = [ ];
          };
          files = mkOption {
            type = listOf str;
            default = [ ];
          };
        };
      }
    );
  usersPersistModule =
    with types;
    submodule (
      { name, config, ... }:
      {
        options = {
          directories = mkOption {
            type = listOf str;
            apply = orig: orig ++ cfg.allUsers.directories;
          };
          files = mkOption {
            type = listOf str;
            apply = orig: orig ++ cfg.allUsers.files;
          };
        };
      }
    );
in
{
  options._.persist = {
    users = mkOption {
      type = types.attrsOf usersPersistModule;
    };
    allUsers = mkOption {
      type = allUsersPersistModule;
    };
  };
  config = {
    environment.persistence.${cfg.root} = {
      inherit (cfg) users;
    };
  };
}
nixos