Skip to main content

Documentation Index

Fetch the complete documentation index at: https://flox.dev/docs/llms.txt

Use this file to discover all available pages before exploring further.

Containers are everywhere these days. They’re the de-facto deployment method in the industry, and they’re often used for local development as well to ensure that every developer gets the same environment. Flox gives you these same benefits without many of the papercuts, but the workflow is slightly different so it’s worth exploring.

Create a new development environment

Let’s say you’ve created a new directory for your project, myproject, and entered it:
mkdir myproject && cd myproject
Create a Flox environment for the project via flox init:
flox init
This creates a .flox directory in myproject. At this point you can enter the environment, but it doesn’t provide any new packages or functionality.

Add packages

Now let’s install some packages. In a typical project there’s usually different subsets of packages:
  • Packages you don’t care about too much, so the latest version will suffice.
  • Packages whose versions you want pinned to a recent version.
  • Packages that you’re behind on updating because upgrading requires significant effort.
We’ll pick a single package from each category:
  • Latest is fine: curl
  • Specific version: yarn 1.22
  • Behind: python3.10
This is pretty straightforward:
flox install curl yarn@1.22 python3@3.10
Adding another package at a later date is as simple as running flox install <package> again.

Configuration

What does it look like to configure your Flox environment compared to a container? A Flox environment is configured via a declarative TOML file called a “manifest”. The manifest for the environment created above looks like this:
version = 1

[install]
curl.pkg-path = "curl"
yarn.pkg-path = "yarn"
yarn.version = "1.22"
python3.pkg-path = "python3"
python3.version = "3.10"

[options]
systems = ["aarch64-darwin", "aarch64-linux", "x86_64-darwin", "x86_64-linux"]
One thing to note here is that the manifest defines a cross-platform environment out of the box to ensure that there are no nasty surprises down the line. A container is configured via a Dockerfile, which is an imperative sequence of commands.
FROM ubuntu:noble

RUN apt update && apt install curl npm

RUN sudo add-apt-repository ppa:deadsnakes/ppa -y && \
    sudo apt update && \
    sudo apt install python3.10
The upside to a Dockerfile is that the commands are familiar (e.g. apt install), but the order of commands matters and you end up stuffing a lot of commands into a single RUN command to avoid creating extra layers.

Use the development environment

Let’s say you want to do some work in the development environment. With Flox you’re put inside a subshell. With containers you can use a shell inside the container or connect to the running container via SSH. However, with containers you also need to mount in your source code, etc.
Activate the environment:
$ flox activate
flox [myproject] $ # now you're in the environment
Notice that there wasn’t a separate “build” step. When you install, uninstall, or edit a Flox environment it’s transactionally built to ensure that it’s always working.

Tear down the development environment

This is pretty straightforward:
flox [myproject] $ exit

Perform initialization

Let’s say you need to move some files around, ensure a directory exists, or some other kind of initialization before doing work inside the development environment. We’ll do a pretend version of this by simply creating a directory foo.
This would be performed in the hook.on-activate script that’s run when activating your environment. You’ll add this by first running flox edit and then modifying the hook section of your manifest to look like this:
[hook]
on-activate = '''
  mkdir foo
'''

Share the environment with your team

Suppose you work on a team and you’ve just set up the development environment. Now you want to share it with your team so you can ensure that everyone has the same environment.
Since flox init creates a .flox directory inside your project, you can simply check this directory into source control.
git add .flox && git commit -m "Add Flox environment" && git push
Anyone with Flox installed can now work on this project with two commands:
$ git clone <your repo>
$ flox activate
Any packages not locally cached would be downloaded. Since the Flox environment produces a lockfile each time it is built, every developer that does a flox activate with the same lockfile will get the same exact software down to the git revisions of the upstream source repositories.If your environment doesn’t need to be tied to this specific project you could also push the environment to FloxHub with flox push. Then your team would activate the environment as a “remote” environment:
$ # You
$ flox push
$ # Your coworker
$ flox activate -r your_user/myproject

Development-time services

In order to mimic the production environment you may want some services running during development (e.g. a web server, a database, etc). For this example let’s say you want a minimal Caddy server running with some environment variables set.
First install Caddy:
flox install caddy
Then edit your manifest to create a new service:
[services.server]
command = "caddy run"
vars.VAR1 = "var1"
vars.VAR2 = "var2"
Since Flox environments aren’t isolated from the host machine’s network you don’t need to map any ports.You can start this service from inside the environment with flox services start, or you can have it start automatically when entering the environment via flox activate --start-services.

Run tests in CI

Say you’ve done some development and now want to run your changes through CI.
A CI system would activate the Flox environment for the repository and then run a specified command inside the environment for each step of the CI job.Since a Flox environment contains a lockfile, a CI system that runs flox activate will get exactly the same software as the developer pushing the changes. This greatly reduces the number of “it works on my machine” instances.Flox provides a number of plugins for CI providers, including GitHub Actions, CircleCI, and GitLab. See the CI/CD tutorial for more information.

Send artifacts to production

Now that you have a working development environment, you need to build a container so that it can be deployed.
You can create a container from an environment via the flox containerize command, and this image will contain the same exact software (again, down to the git revisions of the upstream source repositories) that you used for both local development and CI. If your environment already contains the programs you want to run in production, you’re in good shape.You can also produce build artifacts from a Flox environment. See the builds documentation for more information.