Skip to content

What is an environment manifest?

Flox environments come with a declarative manifest in TOML format that allows a single file to reproduce the environment on another machine. Here is the standard template manifest that is generated when you run flox init:

manifest.toml
# List packages you wish to install.
[install]
# hello.pkg-path = "hello"
# nodejs = { version = "^18.4.2", pkg-path = "nodejs_18" }

# Set environment variables.
[vars]
# message = "Howdy"

# Define scripts to be sourced by your shell.
[profile]
common = """
    export SERVER_URL="http://localhost:$SERVER_PORT"
"""

bash = """
    export MYSHELL="bash"
"""

zsh = """
    export MYSHELL="zsh"
"""

# Define scripts to be executed in a Bash shell after sourcing profile scripts.
[hook]
on-activate = """
    mkdir -p data_dir
"""

# Set options for the environment itself.
[options]

# A whitelist of systems that may activate this environment.
systems = ["aarch64-darwin", "aarch64-linux", "x86_64-linux", "x86_64-darwin"]

Editing your environment's manifest

The manifest contains the following sections represented as TOML tables:

  • [install]: The packages installed to the environment.
  • [vars]: Environment variables for use in the activated environment.
  • [profile]: Custom shell scripts sourced at activation time.
  • [hook]: Custom Bash script executed after profile scripts are sourced.
  • [options]: Environment settings.

The manifest can be edited with flox edit which allows validation to run when saving changes. This interactive editing option is useful for quick edits or to troubleshoot issues.

[install] section

The install section of the manifest is the core of the environment -- the packages that will be available inside of the environment. Packages installed with flox install will automatically get added to the [install] table.

Installing curl via flox install

$ flox install curl

results in the following manifest (view the manifest with flox edit):

[install]
curl.pkg-path = "curl"

The line that's added to the manifest has the form <id>.pkg-path = "<pkg-path>".

Identifying packages by pkg-path

The Flox catalog contains a hierarchy of packages where some are at the top level, and others are contained under package sets. The pkg-path is the location of the package within the catalog, including the package sets that it may be nested under. For instance, pip is nested under python3Packages, so its pkg-path is python3Packages.pip. The pkg-path is also what's displayed in search results, so you should be able to copy and paste a search result into your manifest or use it in a flox install command.

Giving packages convenient names with ids

The <id> in <id>.pkg-path = "<pkg-path>" is the name by which we refer to a package, which may be distinct from the pkg-path of the package. By default the id is inferred from the pkg-path, but you may explicitly set the id during installation with the --id flag. This allows you to provide more convenient names for package in your manifest.

Specifying package versions

The manifest can install packages by semantic version (semver). The package will only be installed if it has a semantic version that falls within the filter provided via the version key. You use the @ character to join the package name with the version when using the CLI.

Let's try installing curl with at least version 8.

$ # quoting is necessary for search terms that contain '>' or '<'
$ flox install 'curl@>=8'

Notice that the manifest now contains a second line with the semantic version filter.

[install]
curl.pkg-path = "curl"
curl.version = ">=8"

You may also request a specific version Here is an example of installing curl version 8.1.1:

$ flox install [email protected]

Notice that the version line now starts with =. This is how you tell Flox to install exact versions or versions that don't adhere to semantic versioning.

[install]
curl.pkg-path = "curl"
curl.version = "=8.1.1"

If you leave out both pkg-path and version, Flox will do a fuzzy search for the supplied ID and use the top search result:

[install]
curl = {}

This could install different packages over time, so it's not recommended.

Optional system specific installations

Sometimes you may have a package that requires a specific CPU architecture or operating system. To do this, include the optional attribute and set it to true. Then include the system types supported for this package.

[install]
gcc.pkg-path = "gcc-unwrapped"
gcc.optional = true
gcc.systems = ["x86_64-linux", "aarch64-linux"]

[vars] section

The [vars] section of the manifest allows for environment variables to be set in the activated environment. These variables are also made available to the scripts in the [hook] and [profile] sections.

In the below example, messsage and message2 are set, used in the profile.common script to generate greeting, which is then used in the hook.on-activate script to echo the final variable:

[vars]
message = "Howdy"
message2 = "partner"

[profile]
common = """
    export greeting="$message $message2"
"""

[hook]
on-activate = """
    cowsay "$greeting" >&2;
"""

[profile] section

Scripts defined in the [profile] section are sourced by your shell immediately after entering the environment and provide a way to add shell aliases to the environment or dynamically compute environment variables. The profile.common script is sourced by all shells, so you must write it to be compatible with all shells. The profile.bash and profile.zsh scripts will only be sourced by the corresponding shell after sourcing the profile.common script.

[profile]
common = """
    export SERVER_URL="http://localhost:$SERVER_PORT"
"""

bash = """
    export MYSHELL="bash"
"""

zsh = """
    export MYSHELL="zsh"
"""

[hook] section

The script defined in hook.on-activate is run in a non-interactive Bash sub-shell after sourcing the profile scripts for each activation (e.g. flox activate). This script inherits all the environment variables set in the [vars] and [profile] sections, but since it runs in a sub-shell it can't modify them. The output and exit code of the hook.on-activate script is discarded. The utility of the hook.on-activate script is that it runs in a consistent shell environment so you don't have to worry about shell compatibility during complicated initialization.

Here is an example hook that prints simple instructions.

[hook]
on-activate = """
  echo "";
  echo "Start the server with 'npm start'";
  echo "";
"""

Note

It is best to write hooks defensively, assuming the user is using the environment from any directory on their machine.

[options] section

The options section of the manifest allows for setting configuration around system types. Environments must specify all the systems that they are meant to be used on.

[options]
systems = ["x86_64-linux", "aarch64-linux"]