Flox: better alternative to Dev Containers
On paper, Dev Containers are great to define and share development environments easily. Actually using them is not that great: lack of reproducibility, integrating host files in containers, difference in implementations between various tools…
While Dev Containers do provide value for dev environment automation, on usage I thought "There's probably a better way to automate development environment setup, is there ?" - and then I started using Flox.
What's Flox ?
Flox lets you create development environments from a manifest.toml
. Not much of a difference between Dev Container's devcontainer.json
at first, but there are a few key differences:
- Flox runs directly on host - you'll have access to all your files and configs without relying on complex bind mount or other boilerploite parameters (often different between individual context). Your SSH keys and your shell aliases ? No problem, they're right here !
- Reproducibility - While it's hard to get deterministic and reproducible container image build, Flox reproducibility is built-in: you have strong guarantees that everyone will run the same version of all your packages and tools.
- Packages from the Nix ecosystem - Dev Container uses collections, but it's hard to find exactly what you need so you'll often reinvent the wheel and rewrite your own Containerfile or Dockerfile. Flox leverages Nix nixpkgs, a collection of reproducible packages widely used and production hardened. With access to thousands of packages easily, adding yours with Flox is easy.
Example setup: NodeJS application
Flox installation is a breeze on any Linux, MacOS or Windows. Once installed, run flox init in your project:
$ flox init
Flox detected a package.json
Flox can add the following to your environment:
* nodejs 20.17.0 with npm bundled
* An npm installation hook
# ...
✨ Created environment 'my-app' (x86_64-linux)
✅ 'nodejs' installed to environment 'my-app'
Flox detects we're using NodeJS and automatically add relevant packages. Of course we'll want to add our own packages - it's just a command away.
Let's add pnpm
and jq
to make them available in our development environment. We'll first search for relevant package name to add them.
$ flox search pnpm
pnpm Fast, disk space efficient package manager for JavaScript
pnpm_9 Fast, disk space efficient package manager for JavaScript
pnpm_8 Fast, disk space efficient package manager for JavaScript
# ...
$ flox search jq
jq Lightweight and flexible command-line JSON processor
# ...
$ flox install pnpm jq
✅ 'pnpm' installed to environment 'my-app'
✅ 'jq' installed to environment 'my-app'
It's also possible to lookup packages directly from NixOS search page.
Out Flox config is ready, let's start our development environment and check if our packages are available:
$ flox activate
✅ You are now using the environment 'my-app'.
To stop using this environment, type 'exit'
up to date, audited 1 package in 163ms
found 0 vulnerabilities
flox [my-app] $ pnpm --version
9.12.1
flox [my-app] $ jq --version
jq-1.7.1
We now just have to push .flox/
into our project's repository to share our development environment with our team. We won't even need to have node
installed locally, Flox will install the right version for us on activation ✨
Flox and CI pipelines
We can use the same environment both locally and on our CI pipelines. For example on GitLab CI:
test:
stage: test
image: node:22-alpine
script:
# run command under the same Flox dev environment you used locally
- flox activate -- npm run build
Flox documents usage for various contexts: GitHub, GitLab, CircleCI…
Bring configs, env vars and secrets to Flox
We now have packages and tools, how about configurations such as environment variables and secrets?
Flox provides a way to set environment variables via manifest.toml
, though it may be limited:
# manifest.toml
[vars]
MYAPP_LOGIN = "localuser"
MYAPP_PASSWORD = "devPassword123!"
We can bring our own tooling we'll run on Flox shell startup using a shell hook. There's plenty to choose from such as:
- novops - Bring your secrets and configs securely from various sources (Hashicorp Vault, AWS, Azure, GCP…) into your shell as environment variables or files. Support multiple environments to easily switch context.
- sops - Simple and flexible tool for managing secrets. Encrypt your secrets into your Git repository for easy and secure access.
- aws-vault - Store and access your AWS credentials in development environments.
For example with Novops you can update manifest.toml to load secret on shell startup:
# Scripts defined in the `[profile]` section are sourced by your shell
[profile]
common = """
# will prompt for environment to use (dev, preprod...) and load secrets from source
source <(novops load)
"""
Bonus: Nice Flox features
Flox comes with great features out-of-the-box
Shell hooks
You can add Shell hooks to run commands or script automatically on Flox shell startup. For example by adding into our manifest.toml:
[hook]
on-activate = """
# install npm deps
npm install
# setup some variables
export MYAPP_HOST=127.0.0.1
export MYAPP_SKIP_TLS=true
"""
A nice way to customize your development environment behavior, such as setting custom environment variables, running package manager installation or start a local database.
See shell hook doc for details
Defining services
You can define services with Flox to help you run software your project might depend on.
For example to start a local Postgres update manifest.toml
:
[services.database]
command = "postgres start"
vars.PGUSER = "myuser"
vars.PGPASSWORD = "super-secret"
vars.PGDATABASE = "mydb"
vars.PGPORT = "9001"
Though this may be accomplished with a good old docker-compose.yml
, it's worth looking into.
See Flox services doc for details.
Conclusion
Easier to use and providing less friction than Dev Containers, Flox is a great tool to easily setup your development environment. It's more deterministic and provides better reproducibility than containers.
Having used this tool across quite a few projects - lots of them previously using Dev Containers - developer and user feedback is of no appeal: they all prefer Flox.