Process management using process-compose-flake

process-compose-flake is a flake-parts module for process-compose.

This flake-parts module allows you to declare one or more process-compose configurations using Nix attribute sets. It will generate corresponding packages that wrap the process-compose binary with the given configuration.

This module is practical for local development e.g. if you have a lot of runtime dependencies that depend on each other. Stop executing these programs imperatively over and over again in a specific order, and stop the need to write complicated shell scripts to automate this. process-compose gives you a process dashboard for monitoring, inspecting logs for each process, and much more, all of this in a TUI.

Quick Example

See example/flake.nix for an example flake. This example shows a demo of sqlite-web using the sample chinhook-database.

To run this example locally,

mkdir example && cd example
nix flake init -t github:Platonic-Systems/process-compose-flake
nix run

This should open http://127.0.0.1:8213/ in your web browser. If not, navigate to the logs for the sqlite-web process and access the URL. Use demo as the password to access sqlite-web. The interface should look like this:

Usage

Let’s say you want to have a devShell that makes a command watch-server available, that you can use to spin up your projects backend-server, frontend-server, and proxy-server.

To achieve this using process-compose-flake you can simply add the following code to the perSystem function in your flake-parts flake.

process-compose.watch-server = {
  settings.processes = {
    backend-server.command = "${self'.apps.backend-server.program} --port 9000";
    frontend-server.command = "${self'.apps.frontend-server.program} --port 9001";
    proxy-server.command =
      let
        proxyConfig = pkgs.writeTextFile {
          name = "proxy.conf";
          text = ''
            ...
          '';
        };
      in
      "${self'.apps.proxy-server.program} -c ${proxyConfig} -p 8000";
  };
};

process-compose-flake will generate the packages.${system}.watch-server output for you.

You can then spin up the processes by running nix run .#watch-server.

The package output in turn can be used to make the watch-server command available in your devShell:

devShells = {
  default = pkgs.mkShell {
    name = "my-shell";
    nativeBuildInputs = [
      self'.packages.watch-server
    ];
  };
};

You can enter your devShell by running nix develop and run watch-server to run your processes.

preHook

If you’d like to run certain commands before starting the processes, you can add them to preHook:

process-compose.watch-server = {
  preHook = ''
    # Cleanup on EXIT, this runs irrespective of exit-code of process-compose
    trap "rm -rf ./data" EXIT
    export USER=foo
  '';
};

postHook

Or if you’d like to run certain commands upon successful execution of process-compose, i.e exits with exit-code: 0, then add them to postHook:

process-compose.watch-server = {
  postHook = ''
    cat foo.txt
  '';
};

Default settings for all processes

You can define default settings that apply to all processes using defaults.processSettings. This is useful when you want to set common configuration like namespace, restart behavior, or other settings across all processes.

process-compose.watch-server = {
  defaults.processSettings = { name, ... }: {
    # Set default namespace for all processes
    namespace = lib.mkDefault "watch-server";
    # Set default restart behavior
    availability.restart = lib.mkDefault "on_failure";
    availability.max_restarts = lib.mkDefault 3;
    # Use the process name in log locations
    log_location = ".logs/${name}.log";
  };

  settings.processes = {
    backend-server.command = "...";
    frontend-server.command = "...";
    # This process overrides the default namespace
    proxy-server = {
      command = "...";
      namespace = "proxy"; # Overrides the default
    };
  };
};

Important: Use lib.mkDefault when setting defaults to ensure individual process settings can override them.

You can access the process name parameter to create dynamic defaults (e.g., per-process log files).

You can disable defaults entirely by setting defaults.enable = false.

Module API

Our submodule mirrors the process-compose YAML schema. A few things to remember:

  • process-compose.<name>.environment: In the YAML config, a list of environment strings are specified. While this is supported, you can also specify the env vars as a Nix attrset
  • process-compose.<name>.processes.<name>.command: The command string does not have access to the process environment, so if your command becomes shellscript-like you probably want to wrap it in a pkgs.writeShellApplication (see #22).
  • process-compose.<name>.shell: This is set to pkgs.bash by default, obviating reproducibility issues due to depending on globally available bash.

See also

  • services-flake: NixOS-like services built on top of process-compose-flake. Use this if you want to run popular services (like postgres).
  • proc-flake: A similar module that uses a Procfile-based runner. It is less feature-rich, but at times more reliable than process-compose.