Top Related Projects
A fast, persistent use_nix/use_flake implementation for direnv [maintainer=@Mic92 / @bbenne10]
unclutter your .profile
Extendable version manager with support for Ruby, Node.js, Elixir, Erlang & more
Simple Python version management
Manage your app's Ruby environment
A conda-forge distribution.
Quick Overview
Devshell is a command-line tool and Nix flake for creating reproducible development environments. It allows developers to define project-specific shells with custom packages, environment variables, and commands, ensuring consistent development setups across different machines and team members.
Pros
- Reproducible development environments across different machines and team members
- Easy integration with Nix and Nix flakes for declarative configuration
- Supports multiple programming languages and tools
- Allows for project-specific customization of shells and commands
Cons
- Requires knowledge of Nix and its ecosystem, which can have a steep learning curve
- May have limited support for non-Linux operating systems
- Dependency on Nix can be seen as overhead for smaller projects
- Documentation could be more comprehensive for newcomers
Getting Started
To get started with Devshell, follow these steps:
-
Install Nix on your system (if not already installed):
curl -L https://nixos.org/nix/install | sh
-
Enable Nix flakes (if not already enabled):
mkdir -p ~/.config/nix echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf
-
Create a
flake.nix
file in your project root:{ description = "My project devshell"; inputs.devshell.url = "github:numtide/devshell"; outputs = { self, nixpkgs, devshell }: let system = "x86_64-linux"; pkgs = import nixpkgs { inherit system; }; in { devShell.${system} = devshell.legacyPackages.${system}.mkShell { imports = [ (devshell.lib.importTOML ./devshell.toml) ]; }; }; }
-
Create a
devshell.toml
file to define your development environment:[devshell] packages = [ "nodejs" "yarn" ] [[commands]] name = "hello" help = "Print hello world" command = "echo Hello, World!"
-
Enter the development shell:
nix develop
This setup creates a basic development environment with Node.js and Yarn, and a custom "hello" command. Adjust the devshell.toml
file to fit your project's needs.
Competitor Comparisons
A fast, persistent use_nix/use_flake implementation for direnv [maintainer=@Mic92 / @bbenne10]
Pros of nix-direnv
- Seamless integration with existing direnv workflows
- Automatic loading of Nix environments without manual activation
- Supports caching of Nix environments for faster subsequent loads
Cons of nix-direnv
- Requires additional setup and configuration compared to devshell
- May have a steeper learning curve for users unfamiliar with direnv
- Limited to Nix-based environments, less flexible for non-Nix projects
Code Comparison
nix-direnv:
use nix
devshell:
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
buildInputs = [ pkgs.hello ];
}
Key Differences
- nix-direnv focuses on integrating Nix with direnv, while devshell provides a more comprehensive development environment solution
- devshell offers a higher-level abstraction for defining development environments, making it easier to manage complex setups
- nix-direnv is more lightweight and can be easily added to existing projects, whereas devshell may require more significant changes to project structure
Use Cases
- nix-direnv: Ideal for projects already using direnv or those requiring quick Nix environment integration
- devshell: Better suited for projects needing a more structured and feature-rich development environment, especially those heavily relying on Nix
unclutter your .profile
Pros of direnv
- Language-agnostic and works with various shells (bash, zsh, fish)
- Automatically loads/unloads environment variables when entering/exiting directories
- Lightweight and easy to integrate into existing workflows
Cons of direnv
- Requires manual setup of
.envrc
files in each project directory - Limited to environment variable management, lacks advanced development environment features
- Potential security risks if
.envrc
files are not properly gitignored
Code Comparison
direnv:
# .envrc
export DATABASE_URL="postgresql://user:pass@localhost/mydb"
export API_KEY="secret_key"
devshell:
# devshell.toml
[devshell]
packages = ["postgresql", "nodejs", "yarn"]
[[commands]]
name = "start-dev"
command = "yarn start"
Key Differences
- direnv focuses on environment variable management, while devshell provides a more comprehensive development environment setup
- devshell is Nix-based and offers reproducible environments, whereas direnv is more flexible but less standardized
- direnv works by modifying the shell environment directly, while devshell creates isolated environments for each project
Use Cases
- direnv: Quick and easy environment variable management across multiple projects
- devshell: Comprehensive development environment setup for Nix-based projects with reproducible builds
Extendable version manager with support for Ruby, Node.js, Elixir, Erlang & more
Pros of asdf
- Supports multiple programming languages and tools in a single system
- Allows version management for each project independently
- Has a large community and extensive plugin ecosystem
Cons of asdf
- Requires manual installation and configuration of plugins
- May have slower shell startup times due to its comprehensive nature
- Can be more complex to set up initially compared to simpler alternatives
Code Comparison
asdf:
asdf plugin add nodejs
asdf install nodejs 14.17.0
asdf global nodejs 14.17.0
devshell:
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
buildInputs = [ pkgs.nodejs-14_x ];
}
Key Differences
devshell focuses on creating reproducible development environments using Nix, while asdf is a more general-purpose version manager for multiple languages and tools. devshell integrates seamlessly with Nix ecosystems, providing a declarative approach to environment setup. asdf offers greater flexibility across different systems and languages but requires more manual configuration.
devshell excels in Nix-based workflows and offers better integration with Nix packages, while asdf provides a more universal solution for managing tool versions across various projects and languages. The choice between the two depends on the specific needs of the project and the preferred development ecosystem.
Simple Python version management
Pros of pyenv
- Specialized for Python version management
- Supports a wide range of Python versions and implementations
- Allows per-project Python version configuration
Cons of pyenv
- Limited to Python environments only
- Requires manual installation of Python versions
- Less integrated with system-wide package management
Code Comparison
pyenv:
pyenv install 3.9.0
pyenv local 3.9.0
python --version
devshell:
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
buildInputs = [ pkgs.python39 ];
}
Key Differences
- devshell provides a more comprehensive development environment setup, while pyenv focuses solely on Python version management
- devshell leverages Nix for reproducible environments across different systems, whereas pyenv relies on system-specific installations
- pyenv offers finer-grained control over Python versions, including patch-level specificity
- devshell integrates better with other tools and languages in a project's ecosystem
Use Cases
- Choose pyenv for projects requiring specific Python versions or multiple Python environments
- Opt for devshell when working on projects with diverse language requirements or when seeking a more holistic development environment solution
Manage your app's Ruby environment
Pros of rbenv
- Specifically designed for Ruby version management
- Lightweight and focused on a single language ecosystem
- Large community and extensive plugin support
Cons of rbenv
- Limited to Ruby environment management
- Requires additional tools for dependency management (e.g., Bundler)
- Less flexible for multi-language projects
Code Comparison
rbenv:
rbenv install 3.0.0
rbenv global 3.0.0
rbenv rehash
devshell:
{ pkgs ? import <nixpkgs> {} }:
pkgs.devshell.mkShell {
imports = [ (pkgs.devshell.importTOML ./devshell.toml) ];
}
Key Differences
- rbenv focuses on Ruby version management, while devshell provides a more general-purpose development environment solution
- devshell leverages Nix for reproducible environments across multiple languages and tools
- rbenv requires manual installation of Ruby versions, whereas devshell can declaratively specify all required dependencies
- devshell offers more flexibility for complex project setups and multi-language environments
- rbenv has a simpler learning curve for Ruby-specific projects, while devshell may require more initial setup but provides greater long-term benefits for diverse development needs
A conda-forge distribution.
Pros of Miniforge
- Supports multiple operating systems (Windows, macOS, Linux)
- Provides pre-configured environments for data science and machine learning
- Integrates seamlessly with the Conda package manager ecosystem
Cons of Miniforge
- Larger installation footprint compared to lightweight alternatives
- May have slower environment creation and package installation times
- Less flexible for custom development environments outside of data science
Code Comparison
Miniforge (environment.yml):
name: myenv
channels:
- conda-forge
dependencies:
- python=3.9
- numpy
- pandas
Devshell (devshell.toml):
[devshell]
packages = ["python39", "python39Packages.numpy", "python39Packages.pandas"]
Miniforge focuses on creating reproducible environments for data science and scientific computing, while Devshell provides a more general-purpose development environment solution. Miniforge leverages the Conda package manager, which offers a wide range of pre-built packages for various platforms. Devshell, on the other hand, integrates with Nix and provides a more flexible approach to defining development environments, allowing for easier customization across different projects and languages.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
devshell - like virtualenv, but for all the languages
STATUS: unstable
The goal of this project is to simplify per-project developer environments.
Imagine, a new employee joins the company, or somebody transfers teams, or somebody wants to contribute to one of your Open Source projects. It should take them 10 minutes to clone the repo and get all of the development dependencies.
Documentation
See docs (docs source)
Features
Compatible
Keep it compatible with:
- nix-shell
- direnv
- nix flakes
Clean environment
pkgs.stdenv.mkDerivation
and pkgs.mkShell
build on top of the
pkgs.stdenv
which introduces all sort of dependencies. Each added package,
like the pkgs.go
in the "Story time!" section has the potential of adding
new environment variables, which then need to be unset. The stdenv
itself
contains either GCC or Clang which makes it hard to select a specific C
compiler.
This is why mkShell
builds its environment from a builtins.derivation
.
direnv loads will change from:
direnv: export +AR +AS +CC +CONFIG_SHELL +CXX +HOST_PATH +IN_NIX_SHELL +LD +NIX_BINTOOLS +NIX_BINTOOLS_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu +NIX_BUILD_CORES +NIX_BUILD_TOP +NIX_CC +NIX_CC_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu +NIX_CFLAGS_COMPILE +NIX_ENFORCE_NO_NATIVE +NIX_HARDENING_ENABLE +NIX_INDENT_MAKE +NIX_LDFLAGS +NIX_STORE +NM +OBJCOPY +OBJDUMP +RANLIB +READELF +RUSTC +SIZE +SOURCE_DATE_EPOCH +STRINGS +STRIP +TEMP +TEMPDIR +TMP +TMPDIR +buildInputs +buildPhase +builder +builtDependencies +cargo_bins_jq_filter +cargo_build_options +cargo_options +cargo_release +cargo_test_options +cargoconfig +checkPhase +configureFlags +configurePhase +cratePaths +crate_sources +depsBuildBuild +depsBuildBuildPropagated +depsBuildTarget +depsBuildTargetPropagated +depsHostHost +depsHostHostPropagated +depsTargetTarget +depsTargetTargetPropagated +doCheck +doInstallCheck +docPhase +dontAddDisableDepTrack +dontUseCmakeConfigure +installPhase +name +nativeBuildInputs +out +outputs +patches +preInstallPhases +propagatedBuildInputs +propagatedNativeBuildInputs +remapPathPrefix +shell +src +stdenv +strictDeps +system +version ~PATH
to:
direnv: export +DEVSHELL_DIR +PRJ_DATA_DIR +PRJ_ROOT +IN_NIX_SHELL +NIXPKGS_PATH ~PATH
There are new environment variables useful to support the day-to-day activities:
DEVSHELL_DIR
: contains all the programs.PRJ_ROOT
: points to the project root.PRJ_DATA_DIR
: points to$PRJ_ROOT/.data
by default. Is used to store runtime data.NIXPKGS_PATH
: path tonixpkgs
source.
Common utilities
The shell comes pre-loaded with some utility functions. I'm not 100% sure if those are useful yet:
menu
- list all the programs available
MOTD
When entering a random project, it's useful to get a quick view of what commands are available.
When running nix-shell
or nix develop
, mkShell
prints a welcome message:
ð¨ Welcome to devshell
[[general commands]]
hello - prints hello
menu - prints this menu
[formatters]
nixpkgs-fmt - Nix code formatter for nixpkgs
[linters]
golangci-lint - golang linter
[utilites]
hub - github utility
[devshell]$
Configurable with a TOML file
You might be passionate about Nix, but people on the team might be afraid of that non-mainstream technology. So let them write TOML instead. It should handle 80% of the use-cases and falling back on Nix is always possible.
Bash completion by default
Life is not complete otherwise. Huhu.
Packages that contain bash completions will automatically be loaded by
mkShell
in nix-shell
or nix develop
modes.
Capture development dependencies in CI
With a CI + Binary cache setup, one often wants to be able to capture all the
build inputs of a shell.nix
. With mkShell
capturing all of the
development dependencies is as easy as:
nix-build shell.nix | cachix push <mycache>
Runnable as a Nix application
Devshells are runnable (via nix run
). This makes it possible to run commands defined in your devshell without entering a nix-shell
or nix develop
session:
nix run '.#<myapp>' -- <devshell-command> <and-args>
This project itself exposes a Nix application; you can try it out with:
nix run 'github:numtide/devshell' -- hello
See here for more details.
TODO
A lot of things!
- Documentation
- Explain how all of this works and all the use-cases.
- Testing
- Write integration tests for all of the use-cases.
- Lazy dependencies
- This requires some coordination with the repository structure. To keep the dev closure small, it would be nice to be able to load some of the dependencies on demand.
- Doctor / nix version check
- Not everything can be nicely sandboxed. Is it possible to get a fast doctor script that checks that everything is in good shape?
- Support other shells
- What? Not everyone is using bash? Right now, support is already available in direnv mode.
Contributing
Docs
- Change files in
docs/
- Run
nix run .#docs
- Open
docs
Benchmark
- See benchmark/README.md
- Run
nix run .#bench
Commercial support
Looking for help or customization?
Get in touch with Numtide to get a quote. We make it easy for companies to work with Open Source projects: https://numtide.com/contact
Top Related Projects
A fast, persistent use_nix/use_flake implementation for direnv [maintainer=@Mic92 / @bbenne10]
unclutter your .profile
Extendable version manager with support for Ruby, Node.js, Elixir, Erlang & more
Simple Python version management
Manage your app's Ruby environment
A conda-forge distribution.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot