← BACK TO THE HOMEPAGE

Oct 24, 2026 • 4 min read

Automating Development Environments with Nix and Custom Tmux Scripts

Introduction

Setting up terminal development environments often requires repetitive manual steps: opening splits, launching dev servers, and setting up environment variables. Doing this manually every time you start work leads to context switching overhead and inconsistent layouts. To make environment setup seamless and reliable, combine Nix with a custom Tmux script.

Instead of manually setting up panes and dependencies, this approach builds an isolated development workspace automatically upon entering a Nix shell.

The full source code for this environment is available in the rosera/nix-shell-pack repository on GitHub.

The Custom Tmux Script (dev.tmux)

The first step is defining a shell script that handles session creation and pane layouts.

This script checks for an existing session or automatically generates a unique session name using random adjective-noun pairs. It then creates a three-pane window layout and attaches to it:

NODE_TYPE // bash
#!/usr/bin/env bash

# DEFAULT_PORT
DEFAULT_PORT=8080

# Detect OS shell
if [[ "$OSTYPE" == "darwin"* ]]; then
  SHELL_CMD="zsh"
else
  SHELL_CMD="bash"
fi

# Generate random Docker-like name
generate_session_name() {
  ADJECTIVES=(happy brave calm eager fancy gentle jolly kind lucky nice proud quick shiny witty bold clever)
  NOUNS=(tiger panda eagle otter fox whale lion falcon wolf bear koala shark)

  adj=${ADJECTIVES[$RANDOM % ${#ADJECTIVES[@]}]}
  noun=${NOUNS[$RANDOM % ${#NOUNS[@]}]}
  echo "${adj}-${noun}-dev"
}

SESSION=${2:-$(generate_session_name)}
echo "Using SESSION=$SESSION"

# Check if the session already exists
tmux has-session -t "$SESSION" 2>/dev/null

# Create new session if it doesn't exist
if [ $? != 0 ]; then
  tmux new-session -d -s "$SESSION" "$SHELL_CMD"
  tmux split-window -h -t "$SESSION" "$SHELL_CMD"
  tmux split-window -v -t "$SESSION" "$SHELL_CMD"

  # Optional: Send commands to specific panes
  # tmux send-keys -t "$SESSION":0.0 "hugo serve -p $DEFAULT_PORT" C-m

  tmux send-keys -t "$SESSION":0
fi

tmux attach-session -t "$SESSION"

Wrapping the Script in Nix (shell.nix)

Once your script (dev.tmux) is ready, use Nix to bundle the script into an executable package (dev-tmux) and construct the environment shell.

Using pkgs.writeShellScriptBin, Nix turns the local script file into a binary available in the PATH inside the shell context:

NODE_TYPE // nix
with import <nixpkgs> {};

let
  # External Script: Reads './dev.tmux' and creates a binary executable 'dev-tmux'
  tmuxLayout = pkgs.writeShellScriptBin "dev-tmux" (builtins.readFile ./dev.tmux);
in
pkgs.mkShell {

  name = "tmux-dev";
  nativeBuildInputs = with pkgs; [
    tmux
    tmuxLayout
  ];

  LANGUAGE = "Tmux";
  VERSION  = "tmux -V";

  shellHook = ''
    # Environment startup info
    echo "Welcome to $LANGUAGE Development Environment"
    $VERSION

    # Trap: Kills the tmux session as soon as you exit the nix-shell
    trap "tmux kill-session -t go-dev" EXIT

    # Execute the custom Tmux layout
    exec dev-tmux
  '';
}

Running the Environment

You can spin up this development environment either from a local clone or directly from the remote repository.

Option 1: Running Locally

If you have cloned the repository locally, navigate to the directory containing shell.nix and dev.tmux, then execute:

NODE_TYPE // bash
nix-shell

Option 2: Running Directly from GitHub

Nix allows running shell expressions directly from a remote Git URL without needing to manually clone the repository first:

NODE_TYPE // bash
nix-shell https://github.com/rosera/nix-shell-pack/archive/main.tar.gz -A development.nix-tmux

Upon executing either command, Nix fetches tmux, constructs the dev-tmux wrapper binary, executes the layout script, and attaches you directly to your configured terminal session.

The Isolated Workspace Loop

When combining Nix and Tmux, your terminal lifecycle becomes fully deterministic and self-contained.

NODE_TYPE // text
            [ nix-shell ]
               /     \
              /       \
             v         v
      [ Dependencies ]  [ dev-tmux Binary ]
             \         /
              \       /
               v     v
       [ Managed Tmux Workspace ]
  1. Instantiation: Running nix-shell evaluates shell.nix, downloads tmux, and compiles dev.tmux into an ephemeral binary executable.
  2. Execution: The shellHook triggers exec dev-tmux, instantly dropping you into your split-pane workspace.
  3. Cleanup: Once you exit the shell, the trap hook cleans up background sessions, leaving no orphan processes behind.

Conclusion

Combining Nix with custom Tmux layout scripts turns interactive environment creation into a repeatable software pattern. By packaging your layouts directly within your project’s declarative environment, onboarding developers or resuming work becomes a single-command process.