Skip to main content

Rust Development in NixOS

Using NixOS to get a full, and non persistent, development environment for Rust.

· By Joe Bellus · 3 min read

Fighting with tooling, versions, and dependencies is a pain. There are solutions to it: Running specific databases via Docker containers, or using dev shells in VSCode (sad panda), or per project environment VMs.

Alternatively, you could just cd project and have the entire environment there.

You'll be cradled in a Nix Shell, a magical pocket dimension where all the necessary tools are automatically summoned: Erlang, Elixir, NodeJS, Postgres, and everything needed for their language servers, linting, and code formatting. All with specific versions tailored for a single project.

The best part? Absolutely nothing gets permanently installed on your system. This is pure wizardry contained within the project directory – all these powerful tools vanish instantly when you exit or leave the path (cd ..). It's like having a portable, self-contained development universe.

Requirements

To get started we will assume a few things:

What We Will Get

When we are finished, you should have a fully functional development setup that automatically loads when entering the path. It will include the Rust compiler, the Cargo toolkit, and RustAnalyzer for LSP.

As with any Nix Shell, this wont permanently install anything to the system. All tooling will be available when inside the project path and wont persist when leaving it.

System Packages

Package Description
rustc The Rust compilier and toolchain
rust-analyzer Rust LSP server
cargo The Cargo toolkit for managing depenedencies and build tasks.

The flake.nix

To get started, find any Rust project you want to setup; or create a new one with cargo new myapp. Then, inside the project root create a flake.nix file:

{
  description = "My Cool Rust App";
  inputs = { nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; };
  outputs = { self, nixpkgs }:
    let
      system = "x86_64-linux";
      pkgs = import nixpkgs { inherit system; };
    in {
      devShells.${system}.default = pkgs.mkShell {
        packages = [ pkgs.rustc pkgs.cargo pkgs.rust-analyzer ];
      };
      packages.${system}.default = pkgs.rustPlatform.buildRustPackage {
        pname = "myapp";
        version = "0.0.1";
        cargoLock.lockFile = ./Cargo.lock;
        src = pkgs.lib.cleanSource ./.;
      };
    };
}

flake.nix

You should change the pname variable to your binary name, the version variable to your application's version, and set description to something catchy.

You will need to at least stage the flake.nix file in git, with git add flake.nix. If this is a brand new project make sure you have ran cargo build at once to generate a cargo.lock file and stage or commit it to your repository as well.

The Development Environment

Now you can entirely uninstall rustc and cargo, if you so desired. When you want to start development run nix develop from the root of the project and everything will be available for you. When your done, exit will return you from the development environment and poof everything is gone – magic!.

Building for Nix

If this is a brand new project make sure you have ran cargo build at once to generate a cargo.lock file and stage or commit it to your repository as well.

The flake.nix configuration grants the ability to package your application for nix. To build your app run nix build in the root of the project. cargo will compile the app and a new path will be created; with your bin file at project_root/result/bin.

Dont forget to add ./result to your .gitignore file.

Setting up DIRENV

With DIRENV, the nix shell will be loaded as soon as we enter the path. No more need to type nix develop. Many IDEs/editors can also take advantage of DIRENV to load the environment automatically when the project is opened. Emacs and Neovim can both do this.

To setup DIRENV create a .envrc file in the project root with the following line:

use flake

.envrc

Enable it explicitly:

direnv allow

Now when you cd into the path the environment will be automatically loaded, when you leave the project path it will be unloaded.

A More Involved Environment

Previously, we created very simple Rust environment for dealing with basic Cargo apps. A more complex app might need additional targets, development libraries, and configuration. For a more involved example, this flake will create a much deeper environment for Rust. With the following added configuration:

  • The ability to install development libraries
  • Additional targets (the wasm target is available as an example)
  • Additional shell environment configuration
{
  description = "A more complicated Rust app";

  inputs = {
    nixpkgs.url = "nixpkgs/nixos-unstable";
    rust-overlay = { url = "github:oxalica/rust-overlay"; };
  };

  outputs = { nixpkgs, rust-overlay, ... }:
    let
      system = "x86_64-linux";
      supportedSystems = [ "x86_64-linux" ];
      forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
      pkgsFor = nixpkgs.legacyPackages;
    in {
      packages.${system}.default =
        let pkgs = import nixpkgs { inherit system; };
        in pkgs.rustPlatform.buildRustPackage {
          pname = "myapp";
          version = "0.4.3";
          cargoLock.lockFile = ./Cargo.lock;
          src = pkgs.lib.cleanSource ./.;
        };
      devShells."${system}".default = let
        pkgs = import nixpkgs {
          inherit system;
          overlays = [ rust-overlay.overlay ];
          config.allowUnfree = true;
        };
      in pkgs.mkShell {
        libraries = with pkgs; [
          # Some example libraries
          dbus
          openssl_3
        ];
        packages = with pkgs; [
          rust-analyzer
          (rust-bin.stable.latest.default.override {
            extensions = [ "rust-src" ];
            targets = [ "wasm32-unknown-unknown" ];
          })
          cargo      
          # Example dependencies
          dbus
          openssl_3 
          trunk
        ];
        # Additional shell environment
        shellHook = ''
          LD=$CC
        '';
      };
    };
}
Updated on Jun 5, 2025