Project environments¶
You can use flox to set up a development environment for an existing project or when creating a project from scratch. Let's see how this can be done with a few commands:
Note
It was previously recommended to use a flox.nix
file to define a project
environment.
Using a flox.nix
file is still supported, but it currently has a number of
limitations for development (for example it doesn't set variables like
PKG_CONFIG_PATH
and PYTHONPATH
).
Although we fully intend to overcome those limitations in the future, in the
mean time we'll show you how you can get work done today using default.nix
.
Initialize a project¶
Let's setup the initial of a project called example-project
using the
flox init
command:
$ mkdir example-project && cd example-project
$ flox init --template project # (1)!
> The current directory is not in a Git repository, would you like to create one in "/home/USER/example-project"? Yes
Created git repo: /home/USER/example-project
wrote: /home/USER/example-project/flake.nix
> Enter package name example-project
wrote: /home/USER/example-project/shells/__PACKAGE_NAME__/default.nix
wrote: /home/USER/example-project/shells/__PACKAGE_NAME__
wrote: /home/USER/example-project/shells
[INFO] [flox_rust_sdk::models::project] moved: /home/USER/example-project/shells/__PACKAGE_NAME__ -> /home/USER/example-project/shells/example-project
Run 'flox develop' to enter the project environment.
-
flox init
can be used to jumpstart your project with some initial structure for your project.See more details in the man page.
Let's look closer at the files that were generated:
shells/example-project/default.nix
¶
Project environments should be defined in a
shells/<project name>/default.nix
file.
{
gnumake,
mkShell,
stdenv,
zlib, # (1)!
}:
#
# Create a development shell using three sections:
# `packages`, `buildInputs`, and `shellHook`.
#
mkShell { # (2)!
# Compilers and libraries go here
buildInputs = [
stdenv.cc
zlib
];
# Add extra tools here
packages = [
gnumake
];
# Any variable set in this block that isn't a reserved word will be set as an
# environment variable in the environment.
WELCOME_MESSAGE = "Run make to build this project";
# A shell hook is a script to run when entering an environment.
# It can be used to perform any custom activation steps needed for your
# project.
shellHook = ''
make --version
echo
echo "$WELCOME_MESSAGE"
'';
}
- The packages in this block are made available in the block below, so listing packages here can be seen as importing them.
mkShell
is a helper function from Nixpkgs for creating developer environments.
flake.nix
- a file that provides compatibility with Nix.¶
flake.nix
is created when you initialize an environment. This is created in the
root directory of your project.
{
description = "A flox project";
# (1)!
inputs.flox-floxpkgs.url = "github:flox/floxpkgs";
# (2)!
outputs = args @ {flox-floxpkgs, ...}: flox-floxpkgs.project args (_: {});
# (3)!
}
-
(optional) A flake description of the project.
-
flox-floxpkgs
is a place where all flox-related packages, modules and libraries are located. -
flox-floxpkgs.project
is a helper function which will scan your project for flox environments.
Add packages to an environment¶
A typical workflow to add packages to a development environment would be:
Note
We use flox nix search
rather than flox search
below because
flox search
only searches packages from the
catalog and does not include certain
Nix helper functions and packages from Nixpkgs.
We intend to fix this deficiency of flox search
in the future.
$ flox nix search nixpkgs openssl
...
* legacyPackages.aarch64-darwin.openssl (3.0.8)
A cryptographic library that implements the SSL and TLS protocols
...
$ # add openssl to default.nix
$ git diff shells
diff --git a/shells/example-project/default.nix b/shells/example-project/default.nix
index c4a4549..aa663aa 100644
--- a/shells/example-project/default.nix
+++ b/shells/example-project/default.nix
@@ -1,6 +1,7 @@
{
gnumake,
mkShell,
+ openssl,
stdenv,
zlib,
}:
@@ -11,6 +12,7 @@
mkShell {
# Compilers and libraries go here
buildInputs = [
+ openssl
stdenv.cc
zlib
];
Enter the environment¶
Installing a package to an environment does not make it instantly available.
For it to be available for use we need to activate the environment with the
flox develop
command. In this example, you can validate that your openssl
package was added to the environment by running which openssl
.
Note
Project environments are entered with flox develop
while other flox
environments are entered with flox activate
.
flox develop
performs setup needed for development, for example it adds
paths of libraries to relevant environment variables, in addition to adding
binaries to PATH
.
flox activate
, on the other hand, sets PATH
but does not set paths to
libraries, so it is useful for creating environments with development tools
(but not libraries) or binaries ready for production.
Environments used by flox activate
are managed imperatively with the flox
CLI or declaratively in a flox.nix file.
$ make --version
GNU Make 3.81 # (1)!
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
This program built for i386-apple-darwin11.3.0
$ flox develop # (2)!
GNU Make 4.4.1
Built for aarch64-apple-darwin22.3.0
Copyright (C) 1988-2023 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Run make to build this project
$ which make # (4)!
/nix/store/a51vzhr9hdfyyhp5m803y3k4mp9na19f-gnumake-4.4.1/bin/make
$ git add flake.lock # (5)!
$ exit # (6)!
-
Although
make
is present, it's a very old version from 2006. -
We enter the project environment with
flox develop
. -
The output from running
shellHook
is displayed here. -
Inside the project environment we now have a newer version of the
make
binary which was provided by thegnumake
package. -
flake.lock
is the lock file of the project and locks all dependencies used by the project to a specific version. If you wish to reproduce your environment on another machine or share it reproducibly with somebody else, you should add it alongside your project code. -
When we are done playing or working inside the environment we should not forget to exit it.
Behind the scenes the following file was created:
flake.lock
: stores the exact version of flake inputs (dependencies in Nix terminology). This is similar to howCargo.lock
locks all Rust crate dependencies.
Adding platform specific dependencies¶
A macOS or Linux specific dependency can be added as follows:
$ git diff shells
$ git diff shells
diff --git a/shells/example-project/default.nix b/shells/example-project/default.nix
index c4a4549..31b52bf 100644
--- a/shells/example-project/default.nix
+++ b/shells/example-project/default.nix
@@ -1,4 +1,7 @@
{
+ hostPlatform, # (1)!
+ lib, # (2)!
+ libiconv, # (3)!
gnumake,
mkShell,
openssl,
@@ -11,11 +14,15 @@
#
mkShell {
# Compilers and libraries go here
- buildInputs = [
- openssl
- stdenv.cc
- zlib
- ];
+ buildInputs =
+ [
+ openssl
+ stdenv.cc
+ zlib
+ ]
+ ++ lib.optional hostPlatform.isDarwin [ # (4)!
+ libiconv
+ ];
# Add extra tools here
packages = [
hostPlatform
provides constants about the platform building this environment.lib
contains helper functions for writing Nix expressions.libiconv
is the actual dependency we want to add to the environment.- Use
hostPlatform.isLinux
to add a Linux specific dependency.
Sharing the environment¶
Assuming all Nix files created above are commited, including flake.lock
, anyone can use the environment.
Regardless of whether they're using Linux or macOS, they can simply clone the git repo and run:
Where to next?¶
- To automatically activate an
environment, read flox integrates with
direnv
which does an amazing job at activating environment when switching to a folder.