Fast, Declarative, Reproducible and Composable Developer Environments using Nix

Develop nativelyDeploy containers100,000+ packagesWrite scripts and tasks50+ languagesDefine processesReuse servicesRun testsEnforce git hooksUse profilesCompose environmentsDefine outputsAd-hoc environmentsManage secrets

Terminal
$ time devenv shell -- exit
• Building shell ...
real    0m4.832s

$ time devenv shell -- exit
• Using cached shell.
real    0m0.047s

Instant environments with caching

Activate your environment in under 100ms with precise Nix evaluation caching.

Smart invalidation
Automatically detects all files accessed during evaluation. Cache is automatically invalidated when any tracked file changes. Only re-evaluates what's necessary, keeping your workflow fast.
Zero configuration
Works out of the box with no setup required. No daemons, no manual file watching, just instant environments.

Simple JSON-like language

Declaratively define your development environment by toggling basic options.

Environment variables
Use env attribute set to define environment variables.

Include secrets from .env file with dotenv.enable = true;.

Packages
Pick from 100,000+ prebuilt packages for Linux/macOS and x64/ARM64. Works with WSL2.
Shell initialization
Run scripts when entering the environment with enterShell.
Automatic activation
Using direnv will automatically load the environment when you enter the project directory.
devenv.nix
{ pkgs, config, ... }: {
  env.GREET = "determinism";

  packages = [
    pkgs.ncdu
  ];

  enterShell = ''
    echo hello ${config.env.GREET}
    ncdu --version
  '';
}
devenv shell
hello determinism
ncdu 2.3

devenv.nix
{ pkgs, ... }: {
  scripts.build = {
    exec = "yarn build";
    packages = [ pkgs.yarn ];
  };

  tasks."myapp:build" = {
    exec = "build";
    before = [ "devenv:enterShell" ];
  };

  # Runs on `git commit` and `devenv test`
  git-hooks.hooks = {
    black.enable = true;
    # Your custom hooks
    generate-css = {
      enable = true;
      name = "generate-css";
      entry = "build";
    };
  };
}
devenv shell
...
Running tasks     devenv:enterShell
Succeeded         devenv:git-hooks:install 15ms
Succeeded         myapp:build               23ms
Succeeded         devenv:enterShell         23ms
3 Succeeded                                 50.14ms
$

Scripts and Tasks

Define scripts, tasks, and git hooks to automate your development workflow.

Scripts
Define scripts that can be invoked inside the environment, with optional runtime packages that are only available when the script runs.
Tasks
Form dependencies between automation code, executed in parallel and written in your favorite language.
Git hooks
Pick from builtin and language-specific linters and formatters using git-hooks.nix.

Search packages and options

Explore packages and options to customize your environment.

devenv search devenv
+--------------+---------------+------------------------------------------------------------------------+
| Package      | Version       | Description                                                            |
+--------------+---------------+------------------------------------------------------------------------+
| pkgs.devenv  | 1.0.3         | Fast, Declarative, Reproducible, and Composable Developer Environments |
+--------------+---------------+------------------------------------------------------------------------+
+--------------------------+---------+-----------+------------------------------------------------------------+
| Option                   | Type    | Default   | Description                                                |
+--------------------------+---------+-----------+------------------------------------------------------------+
| devenv.debug             | boolean | false     | Whether to enable debug mode of devenv enterShell script.  |
+--------------------------+---------+-----------+------------------------------------------------------------+
| devenv.warnOnNewVersion  | boolean | true      | Whether to warn when a new version of devenv is available. |
+--------------------------+---------+-----------+------------------------------------------------------------+
| devenv.latestVersion     | string  | "1.0.3"   | The latest version of devenv.                              |
+--------------------------+---------+-----------+------------------------------------------------------------+
• Found 1 package and 3 options for 'devenv'.

Languages

Supports over 50 programming languages.

Packed with tooling
Comes with commonly used tooling for each language including LSP servers, formatters, linters, and compilers.
Version support
Languages like Python, Terraform, Rust, PHP, and Ruby all have version support.
Examples
Check out the examples collection to get started.
devenv.nix
{ pkgs, config, ... }: {
  languages.python = {
    enable = true;
    version = "3.11";
    venv.enable = true;
    venv.requirements = ''
      requests
      torch
    '';
    uv.enable = true;
  };

  languages.rust = {
    enable = true;
    channel = "nightly";
    rustflags = "-Z threads=8";
    targets = [ "wasm32-unknown-unknown" ];
  };

  languages.php = {
    enable = true;
    version = "8.1";
    ini = ''
      memory_limit = 256M
    '';
    fpm.pools.web = {
      settings = {
        "pm" = "dynamic";
      };
    };
  };
}
devenv.nix
{ pkgs, ... }: {
  packages = [
    pkgs.cargo-watch
  ];

  processes = {
    cargo-watch.exec = "cargo watch -x run";
  };
}
devenv up
• Building processes ...
• Starting processes ...
...

Run processes

Define your processes declaratively and start them with devenv up.

Declarative processes
Inspired by Procfile, define development processes that have access to your environment.
Process management
By default process-compose is used to manage processes, giving you a simple interface to inspect logs and restart processes (Ctrl+R). Process compose interface

Run services

Choose from many community-maintained services like PostgreSQL, Redis, MySQL, RabbitMQ, WireMock, MinIO, Caddy, ElasticSearch, OpenTelemetry Collector, Prometheus, and more added regularly.

Pre-configured processes
Services define processes that start automatically when enabled via devenv up.
Simple configuration
Each service provides various configuration options and hooks to pass additional custom configuration.
Extensible
Define your own development processes as services, enabling simple reuse with minimal configuration.
devenv.nix
{ pkgs, ... }: {
  services.postgres = {
    enable = true;
    package = pkgs.postgresql_15;
    initialDatabases = [{ name = "mydb"; }];
    extensions = extensions: [
      extensions.postgis
      extensions.timescaledb
    ];
    settings.shared_preload_libraries = "timescaledb";
    initialScript = "CREATE EXTENSION IF NOT EXISTS timescaledb;";
  };
}
devenv up
...

devenv.nix
{ pkgs, ... }: {
  packages = [
    pkgs.mkdocs
    pkgs.curl
  ];

  processes = {
    docs.exec = "mkdocs serve";
  };

  enterTest = ''
    wait_for_port 8000
    curl http://localhost:8000 | grep "Hello, world!"
  '';
}
devenv test
...

Run tests

Running scripts in your environment with all processes active is as simple as devenv test.

Integrated testing
Execute your preferred language test runner or a simple script to verify your environment.

All process management is handled automatically, so you can focus on writing tests.

Container interoperability

Generate containers from your development environment and build/copy/run them.

Containerized environments
The shell container lets you run your environment in a container.

Use devenv container run shell to enter your environment in a container.

Containerized processes
The processes container lets you run your processes in a container.

Use devenv container run processes to run your processes in a container.

Custom containers
Define containers.mycontainer.* to customize your container.
devenv.nix
{ pkgs, ... }: {
  packages = [
    pkgs.mkdocs
    pkgs.curl
  ];

  processes = {
    docs.exec = "mkdocs serve";
  };
}
devenv container build processes
...
devenv container copy processes
...
devenv container run processes
...

frontend/devenv.yaml
imports:
  - /nix           # Shared config from git root
devenv.yaml
inputs:
  myorg-devenv:
    url: github:myorg/myorg-devenv
imports:
  - ./frontend
  - ./backend
  - myorg-devenv/shared-service

Poly/Mono repo composability

Compose multiple environments into a single environment with first-class monorepo support.

Local imports
For monorepos, define environments per folder and import them to merge into a single unified environment. Use / to reference from git root.
Remote imports
For polyrepos, define environments per repository and import them to merge into a single unified environment.
Git root variable
Use ${config.git.root} for consistent path references in tasks and processes.
devenv.nix
{ pkgs, config, ... }: {
  profiles = {
    backend.module = {
      services.postgres.enable = true;
      services.redis.enable = true;
    };

    frontend.module = {
      languages.javascript.enable = true;
      processes.dev-server.exec = "npm run dev";
    };

    fullstack.extends = [ "backend" "frontend" ];

    hostname."ci-server".module = {
      env.CI = "true";
    };

    user."alice".module = {
      packages = [ pkgs.gh ];
    };
  };
}
devenv --profile backend shell
...
devenv --profile fullstack up
...

Organize with profiles

Define profiles to selectively activate parts of your environment for different workflows.

Selective activation
Work on frontend, backend, or both with --profile flags. Compose multiple profiles using extends.
Automatic activation
Profiles can activate automatically based on hostname or username, perfect for team-specific or environment-specific configurations.
Centralized best practices
Create custom options in shared repositories to enforce team standards and reduce configuration duplication.

Packaging using Nix

Use the same interface for all languages for packaging applications. Define outputs to build your applications.

Best tools chosen for you
devenv evaluates and chooses the best packaging tools (crate2nix for Rust, uv2nix for Python) so you don't have to.
Language integration
Each language provides an import function to package your application using the best tools for that ecosystem.
Build outputs
Use devenv build to build your application outputs for distribution.
Distribution ready
Outputs are packaged as Nix derivations, making them ready for distribution and deployment. Read more about closing the Nix gap from tools to packaged applications.
devenv.nix
{ config, ... }: {
  # https://devenv.sh/languages
  languages = {
    rust.enable = true;
    python.enable = true;
  };

  # https://devenv.sh/outputs
  outputs = {
    rust-app = config.languages.rust.import ./rust-app {};
    python-app = config.languages.python.import ./python-app {};
  };
}
Ad-hoc environments
# Instant Python environment
devenv --option languages.python.enable:bool true \
       --option packages:pkgs "ncdu git ripgrep" \
       shell

# Quick Elixir REPL
devenv -O languages.elixir.enable:bool true shell iex

# CI matrix testing
devenv -O languages.python.enable:bool true \
       -O languages.python.version:string "3.11" \
       test

Ad-hoc environments

Create temporary environments directly from the command line with no configuration required. Perfect for experiments and CI pipelines.

Quick experiments
Test languages or tools without creating configuration files. Just run a single command and start coding.
CI/CD matrices
Easily test across multiple language versions or configurations using GitHub Actions matrices or similar CI tools.
Override existing config
Temporarily modify your existing devenv.nix settings without changing any files.

Secrets management

Declarative secrets with SecretSpec - no more .env files

Declare once, use anywhere
Define secrets in secretspec.toml and retrieve from system Keychain, 1Password, LastPass, dotenv, or environment variables.
Profile-based configuration
Different requirements per environment - local defaults in development, strict validation in production, no code changes needed.
Runtime safety
Secrets are retrieved at runtime from your chosen provider. Never stored in config files, preventing accidental commits.
secretspec.toml
[project]
name = "my-app"

[profiles.default]
KEYCLOAK_ADMIN_PASSWORD = {
  description = "Keycloak admin password",
  required = true,
  as_path = true
}

[profiles.development]
KEYCLOAK_ADMIN_PASSWORD = { default = "admin" }
devenv.nix
{ config, ... }: {
  secretspec.enable = true;

  services.keycloak = {
    enable = true;
    settings.KC_BOOTSTRAP_ADMIN_PASSWORD._secret =
      config.secretspec.secrets.KEYCLOAK_ADMIN_PASSWORD;
  };
}