Skip to content

Development

NullString1 edited this page Jan 13, 2026 · 2 revisions

Development Environments

Setting up and managing development environments in NullOS.

Overview

NullOS provides multiple ways to create isolated development environments:

  • direnv + nix-shell - Per-project automatic environments
  • nix develop - Flake-based development
  • Docker - Containerized development
  • Global tools - System-wide development packages

Direnv Integration

NullOS includes direnv for automatic project environments.

How It Works

When you cd into a project directory:

  1. direnv detects .envrc
  2. Loads specified Nix environment
  3. Provides project-specific tools
  4. Automatically cleans up when leaving directory

Using Direnv

1. Create .envrc in project:

# To use flake's devShell
use flake

Or for shell.nix:

# To use legacy nix-shell
use nix

2. Allow direnv:

direnv allow

3. Tools are now available:

# Automatically in PATH when in directory
node --version
python --version

Nix Shell

Basic shell.nix

Create shell.nix in your project:

{ pkgs ? import <nixpkgs> {} }:

pkgs.mkShell {
  buildInputs = with pkgs; [
    nodejs
    yarn
    nodePackages.typescript
  ];
  
  shellHook = ''
    echo "Node development environment loaded"
    echo "Node: $(node --version)"
  '';
}

Enter shell:

nix-shell

Flake-Based Development

Create flake.nix

{
  description = "My Project";
  
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
  };
  
  outputs = { self, nixpkgs }:
    let
      system = "x86_64-linux";
      pkgs = nixpkgs.legacyPackages.${system};
    in
    {
      devShells.${system}.default = pkgs.mkShell {
        buildInputs = with pkgs; [
          nodejs
          python3
          rustc
          cargo
        ];
        
        shellHook = ''
          echo "Development environment ready!"
        '';
      };
    };
}

Enter development shell:

nix develop

Language-Specific Setups

Python

# shell.nix
{ pkgs ? import <nixpkgs> {} }:

pkgs.mkShell {
  buildInputs = with pkgs; [
    python311
    python311Packages.pip
    python311Packages.virtualenv
    python311Packages.numpy
    python311Packages.pandas
  ];
  
  shellHook = ''
    # Create venv if doesn't exist
    if [ ! -d .venv ]; then
      python -m venv .venv
    fi
    source .venv/bin/activate
  '';
}

.envrc:

use nix
layout python python3.11

Node.js

{ pkgs ? import <nixpkgs> {} }:

pkgs.mkShell {
  buildInputs = with pkgs; [
    nodejs_20
    nodePackages.npm
    nodePackages.pnpm
    nodePackages.typescript
    nodePackages.eslint
  ];
}

Rust

{ pkgs ? import <nixpkgs> {} }:

pkgs.mkShell {
  buildInputs = with pkgs; [
    rustc
    cargo
    rustfmt
    clippy
    rust-analyzer
  ];
  
  RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";
}

Go

{ pkgs ? import <nixpkgs> {} }:

pkgs.mkShell {
  buildInputs = with pkgs; [
    go
    gopls
    gotools
    go-tools
  ];
}

C/C++

{ pkgs ? import <nixpkgs> {} }:

pkgs.mkShell {
  buildInputs = with pkgs; [
    gcc
    cmake
    gnumake
    gdb
    clang-tools
  ];
}

Docker Development

NullOS includes Docker support.

Using Docker

# Start container
docker run -it ubuntu bash

# Docker Compose
docker-compose up

# Build image
docker build -t myapp .

Docker Development Template

docker-compose.yml:

version: '3.8'

services:
  dev:
    image: node:20
    volumes:
      - .:/app
    working_dir: /app
    command: npm run dev
    ports:
      - "3000:3000"

VS Code + Docker

# Add to home/vscode.nix
extensions = with pkgs.vscode-extensions; [
  ms-azuretools.vscode-docker
  ms-vscode-remote.remote-containers
];

Database Development

PostgreSQL

{ pkgs ? import <nixpkgs> {} }:

pkgs.mkShell {
  buildInputs = with pkgs; [
    postgresql
  ];
  
  shellHook = ''
    export PGDATA=$PWD/postgres_data
    export PGHOST=$PWD/postgres
    export LOG_PATH=$PWD/postgres/LOG
    export PGDATABASE=postgres
    export DATABASE_URL="postgresql:///postgres?host=$PGHOST"
    
    if [ ! -d $PGHOST ]; then
      mkdir -p $PGHOST
    fi
    
    if [ ! -d $PGDATA ]; then
      echo 'Initializing postgresql database...'
      initdb $PGDATA --auth=trust >/dev/null
    fi
    
    pg_ctl start -l $LOG_PATH -o "-c listen_addresses= -c unix_socket_directories=$PGHOST"
    
    trap "pg_ctl stop" EXIT
  '';
}

MongoDB

{ pkgs ? import <nixpkgs> {} }:

pkgs.mkShell {
  buildInputs = with pkgs; [
    mongodb
  ];
  
  shellHook = ''
    mkdir -p $PWD/.mongo
    mongod --dbpath=$PWD/.mongo --bind_ip 127.0.0.1 &
    export MONGO_PID=$!
    
    trap "kill $MONGO_PID" EXIT
  '';
}

IDE Configuration

VSCode

Already configured in NullOS with extensions:

# home/vscode.nix
programs.vscode = {
  enable = true;
  extensions = with pkgs.vscode-extensions; [
    jnoortheen.nix-ide
    rust-lang.rust-analyzer
    ms-python.python
    # Add project-specific extensions
  ];
};

Neovim

Configured via NVF in home/nvf.nix.


Android Development

Android Studio

Already included in NullOS:

# modules/software/android-studio.nix
programs.adb.enable = true;

Tools available:

  • Android Studio
  • adb (Android Debug Bridge)
  • SDK tools

Environment Variables

export ANDROID_HOME=$HOME/Android/Sdk
export PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools

Cloud Development

AWS CLI

{ pkgs ? import <nixpkgs> {} }:

pkgs.mkShell {
  buildInputs = with pkgs; [
    awscli2
    terraform
    kubectl
  ];
}

Google Cloud

buildInputs = with pkgs; [
  google-cloud-sdk
];

Testing Tools

General Testing

{ pkgs ? import <nixpkgs> {} }:

pkgs.mkShell {
  buildInputs = with pkgs; [
    # Python testing
    python311Packages.pytest
    python311Packages.pytest-cov
    
    # Node testing
    nodePackages.jest
    nodePackages.mocha
    
    # Load testing
    k6
    wrk
  ];
}

Tips & Tricks

Automatic Environment Loading

With direnv, environment loads automatically:

cd ~/project        # Loads environment
which node          # /nix/store/...-nodejs/bin/node
cd ~               # Unloads environment
which node          # command not found

Sharing Environments

Commit flake.nix or shell.nix to Git:

git clone your-project
cd your-project
nix develop         # Everyone gets same environment

Multiple Shells

{
  devShells.${system} = {
    default = pkgs.mkShell { ... };
    
    python = pkgs.mkShell {
      buildInputs = [ pkgs.python311 ];
    };
    
    node = pkgs.mkShell {
      buildInputs = [ pkgs.nodejs ];
    };
  };
}

Use with:

nix develop .#python
nix develop .#node

Global Development Tools

Installed system-wide in NullOS:

  • Version control: git, gh
  • Editors: neovim, vscode
  • Build tools: gcc, cmake, make
  • Containers: docker, docker-compose
  • Debug: gdb
  • Analysis: binwalk, hexdump

See modules/software/packages.nix for full list or check System Applications.


Common Workflows

Starting New Project

mkdir my-project
cd my-project

# Create flake
nix flake init

# Edit flake.nix for your needs

# Create .envrc
echo "use flake" > .envrc
direnv allow

# Start coding!

Existing Project

git clone project
cd project

# If has flake.nix
nix develop

# If has shell.nix
nix-shell

# Or create .envrc
echo "use nix" > .envrc
direnv allow

Troubleshooting

Direnv Not Loading

# Check if allowed
direnv status

# Allow
direnv allow

# Reload
direnv reload

Wrong Tool Version

# Check what's in PATH
which python
readlink $(which python)

# Ensure in correct directory
pwd

# Check .envrc
cat .envrc

Build Fails

# Clear cache
rm -rf .direnv

# Reload
direnv reload

# Or rebuild
nix develop --rebuild

Next Steps

Clone this wiki locally