devenv.sh

 

Fast, Declarative, Reproducible, and Composable Developer Environments

@domenkozar

fosstodon.org/@domenkozar

FOSDEM 2023

About me

  • 2004: First installation of Linux: Gentoo

  • 2012: Switched to NixOS

  • 2014: Why Puppet/Chef/Ansible aren't good enough (and we can do better) 

  • 2018: cachix.org, free binary cache hosting for OSS

  • 2020: nix.dev, Nix tutorials

  • 2022: NixOS Foundation board member

  • 2022: devenv.sh

Good defaults

macOS / Linux / WSL2

each config/package is pinned to a snapshot to all the inputs

 

automatically configures garbage collection

 

direnv.net integration

 

high-level abstraction over any tool

no need for containers

Declarative

$ cat devenv.nix 
{ pkgs, ... }: 

{
  env.GREET = "determinism";

  packages = [ pkgs.git ];

  enterShell = "echo hello $GREET";
}
$ git --version 
git: command not found

$ devenv shell
hello determinism

(devenv) $ git --version
git version 2.38.1

$ devenv search ncdu
...

Reproducible

$ cat devenv.yaml
inputs:
  nixpkgs:
    url: github:NixOS/nixpkgs/nixpkgs-unstable

Composable

$ cat devenv.yaml
inputs:
  nixpkgs:
    url: github:NixOS/nixpkgs/nixpkgs-unstable
  devenv:
    url: github:cachix/devenv
    flake: false
    
imports:
- ./frontend
- devenv/examples/supported-languages

Fast

$ devenv ci
$ devenv shell
Building shell ...
Entering shell ...
(devenv) $ 

Files

  • devenv.nix
  • devenv.local.nix
  • devenv.yaml
  • devenv.lock
  • .envrc

Garbage Collection

$ devenv gc
Counting old devenvs ...

Found 2097 store paths of sum size 9448 MB.

Garbage collecting ...

Note: If you'd like this command to run much faster,
leave a thumbs up at https://github.com/NixOS/nix/issues/7239

Languages

$ cat devenv.nix
{ pkgs, ... }:

{
  languages.python.enable = true;
  languages.python.venv.enable = true;
  
  languages.typescript.enable = true;
}

36 supported languages and counting.

Rust

{ pkgs, lib, ... }:

{
  packages = lib.optionals pkgs.stdenv.isDarwin [
    pkgs.darwin.apple_sdk.frameworks.Security
  ];

  languages.rust = {
    enable = true;
    version = "latest";
  };

  pre-commit.hooks = {
    clippy.enable = true;
    rustfmt.enable = true;
  };
}

PHP

{ pkgs, lib, ... }:

{
  languages.php = {
    enable = true;
    version = "latest";
  };
}
{ pkgs, lib, ... }:

{
  languages.php = {
    enable = true;
    version = "8.1";
    ini = ''
      memory_limit = 2G
    '';
    extensions = [ "redis" "amqp" ];
  };
}

Processes

$ cat devenv.nix 
{ pkgs, ... }:

{
  processes = {
    hello.exec = "while true; do echo hello && sleep 1; done";
    ping.exec = "ping example.com";
  };
}
$ devenv up
Starting processes ...

20:37:44 system          | ping.1 started (pid=4094686)
20:37:44 system          | silly-example.1 started (pid=4094688)
20:37:44 silly-example.1 | hello
20:37:44 ping.1          | PING example.com (93.184.216.34) 56(84) bytes of data.
20:37:44 ping.1          | 64 bytes from 93.184.216.34 (93.184.216.34): icmp_seq=1 ttl=55 time=125 ms
20:37:45 silly-example.1 | hello
20:37:45 ping.1          | 64 bytes from 93.184.216.34 (93.184.216.34): icmp_seq=2 ttl=55 time=125 ms
...

Services

$ cat devenv.nix
{ pkgs, lib, ... }:

{
  services.caddy.enable = true;
  
  services.redis.enable = true;
  
  services.postgres.enable = true;
  
  services.elasticsearch.enable = true;
  
  services.mysql.enable = true;
}

Integrations: what if any tool could be a toggle?

$ cat devenv.nix
{ pkgs, ... }:

{
  scripts."myscript".exec = ''
    curl "https://httpbin.org/get?$1" | jq '.args'
  '';
  
  hosts."example.com" = "127.0.0.1";
  
  devcontainer.enable = true;
  
  difftastic.enable = true;
  
  starship.enable = true;
}

Thanks! Get started:

domen@cachix.org / @domenkozar

https://devenv.sh

devenv.sh

By ielectric

devenv.sh

  • 100