Skip to content

Managed environments


With flox you can create portable, isolated, and reproducible environments without containers. flox provides two different types of environments that are suited to different purposes. See the environments Concepts guide to learn more about the difference between the two types and when to use either one.

To demonstrate all the awesome stuff flox enables we're going to create a managed environment that contains a web server that queries a Dungeons & Dragons 5th Edition API, then we'll put this server behind a proxy and poke at it with some developer tools to simulate web traffic.

Create an environment

Let's start by creating an environment named managed-env using the flox create command:

$ flox create -e managed-env # (1)!
created environment managed-env (...) # (2)!
  1. The -e here stands for environment and is used to specify the environment name.
  2. This is what the output looks like on my Apple Silicon machine running macOS, it will look different for you depending on your CPU architecture and operating system.

Subscribe to flox-examples channel

A channel is like a package repository. We'll make packages in this channel available under the flox-examples name by subscribing to it with the flox subscribe command:

$ flox channels
      CHANNEL     TYPE                URL
    flox          flox  github:flox/floxpkgs/master
    nixpkgs-flox  flox  github:flox/nixpkgs-flox/master
$ flox subscribe flox-examples github:flox-examples/floxpkgs/master
subscribed channel 'flox-examples'
$ flox channels
       CHANNEL     TYPE                  URL
    flox           flox  github:flox/floxpkgs/master
    flox-examples  user  github:flox-examples/floxpkgs/master
    nixpkgs-flox   flox  github:flox/nixpkgs-flox/master

Install packages to the environment

Now that we have an environment we can install some packages using the flox install command:

  • flox-examples.demo-dnd-server, a web-server that queries a D&D API
  • caddy, a proxy server
  • procps, a collection of utilities for handling processes, provides the pkill command
  • curl, used to make HTTP requests
  • jq, used to navigate and process JSON documents
$ flox install -e managed-env flox-examples.demo-dnd-server caddy procps curl jq
Installed 'flox-examples.demo-dnd-server', 'caddy', 'procps', 'curl', 'jq' package(s) into 'managed-env' environment.

Note that installing packages to an environment doesn't immediately make them available, it just means that when you activate that environment those packages will be available.

Enter the environment

You enter an environment with the flox activate command. When entering an environment, the packages installed in the environment become available. Let's activate the environment and verify that caddy is installed:

$ flox activate -e managed-env
flox [managed-env default] $ caddy version

Query the server

Now let's start the server (which will run on port 5500) and send it to the background so that we can make requests without needing to activate the environment in another shell:

flox [managed-env default] $ demo-dnd-server &>/dev/null & # (1)!
[1] 62712 # (2)!
flox [managed-env default] $ curl -X GET -s localhost:5500/spells/acid-arrow
{"index":"acid-arrow","name":"Acid Arrow",... # (3)!
flox [managed-env default] $ curl -X GET -s localhost:5500/spells/fireball | jq '.damage.damage_at_slot_level["3"]' # (4)!
"8d6" # (5)!
  1. The &>/dev/null invocation redirects stdout and stderr to /dev/null so that we don't see any output from the server while it's running, otherwise we would see its logging mixed in with what we type into the terminal. The & at the end of the command tells the shell to run the server asynchronously in the background.
  2. This is the process ID (PID) of the server process on my machine, it will be different on your machine.
  3. The response from the server contains a lot of information so I've truncated it for space.
  4. Here we use jq to pull out a specific piece of information from the API.
  5. This is the number of dice you roll to calculate damage from your Fireball spell. It's a lot!

Put it behind a proxy

Now let's put this server behind a proxy.

We'll start the proxy on port 6600, send it to the background, and see if it all still works (make sure your server is still running!):

flox [managed-env default] $ caddy reverse-proxy --from :6600 --to :5500 &>/dev/null &
[1] 63742
flox [managed-env default] $ curl -X GET -s localhost:6600/spells/sacred-flame | jq '.name'
"Sacred Flame"

Note that now we're using curl to send requests to port 6600 instead of 5500 since our proxy is up and running!

Start server and proxy automatically

Now we'll introduce a new command: flox edit. This command lets you manually edit the environment definition that the flox commands have been editing for you. Run the command flox edit -e managed-env (which will open $EDITOR), and add the following lines before the closing brace:

shell.hook = ''
  echo "Starting proxy 6600 -> 5500"
  caddy reverse-proxy --from :6600 --to :5500 &>/dev/null &
  echo "Starting server on port 5500"
  demo-dnd-server &>/dev/null &
'';  # (1)!
environmentVariables = {
    SOMEVAR = "contents of SOMEVAR";
};  # (2)!
  1. This shell.hook attribute is where you put shell commands you want executed once the environment has been loaded, but before the interactive part of the shell is presented to the user. You can read about other attributes in flox.nix configuration.
  2. The environmentVariables dictionary ("attribute set" in Nix terminology) lets you set environment variables declaratively. The example here (SOMEVAR) is silly, but you could very easily use this to define environment variables important to configuring your application. For instance, we could define the port that the server listens on, provide a path to some credentials, etc.

In order for this shell hook to load you'll have to exit the environment. First kill caddy and the server using pkill, then exit the environment:

$ pkill -f caddy
$ pkill -f demo-dnd-server
$ exit

Now re-enter the environment with flox activate -e managed-env and make a request to the server to make sure it's working:

$ flox activate -e managed-env
Starting proxy 6600 -> 5500
[2] 64665
Starting server on port 5500
[3] 64666
flox [managed-env default] $ curl -X GET -s localhost:6600/spells/mage-hand
{"index":"mage-hand","name":"Mage Hand",...


Our proxy and server now start automatically, but let's say that we'd like to undo that change. Rather than manually editing our environment definition to remove the shell hook, we can roll back to the previous generation (version) of the environment using flox rollback:

flox [managed-env default] $ flox rollback -e managed-env
Rolled back environment 'managed-env' from generation 6 to 5. # (1)!
  1. If you've played around with your environment definition via flox edit or by installing more packages you may have different generation numbers. That's totally fine!

A killer feature of managed environments is this concept of transactional updates to environments. Edits that you make to your environment definition either completely succeed and overwrite the previous definition, or completely fail and are thrown away. If you make an edit to your environment definition flox will check that it can be evaluated, will check that all the packages installed in the environment can be built, and will make sure that all the packages installed in the environment can be combined into a single environment. If any of those checks fail, the edit to the environment definition will be throw away so that you aren't left with a broken environment.

Push to share

flox managed environments are synchronized as git repositories. When you push an environment definition a floxmeta repository is created under your GitHub account. We'll push our managed-env definition using the flox push command, but first we'll need to authenticate with GitHub:

$ flox gh auth login
... # (1)!
$ flox push -e managed-env
... # (2)!
  1. You'll be asked to configure which GitHub account you're using, whether you'd like to use https or ssh, etc.
  2. You'll be asked where to host the repository and whether to use https or ssh.

Verify that you now have a floxmeta repository at the git host you specified. Your floxmeta repository is private by default, so if you'd like to share your environment with someone else you'll need to either make the repository public or grant them read access. Now that you've successfully pushed the environment definition, someone else that has read access to your floxmeta repository can use the flox pull command to use your environment!


This was a whirlwind tour of what managed environments can do, and we didn't even cover all of it! Take a look at the other tutorials to learn more about what you can do with either managed or project environments.